Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing TextBlock.Text to multiline String causes rendering issue #3825

Closed
mat1jaczyyy opened this issue Apr 25, 2020 · 23 comments · Fixed by #4517
Closed

Changing TextBlock.Text to multiline String causes rendering issue #3825

mat1jaczyyy opened this issue Apr 25, 2020 · 23 comments · Fixed by #4517
Assignees

Comments

@mat1jaczyyy
Copy link
Contributor

I've got a TextBlock with text like this:

<TextBlock Text="Original" VerticalAlignment="Center" x:Name="Thing" />

From code-behind, if I set the Text to a multi-line string like this:

Thing.Text = "This is a long line 1\nThis is a long line 2\nThis is a long line 3";

The TextBlock will only render the first line fully, while the second line will only visually contain the region that was previously occupied by the original text. Screenshot examples:
image
image

Opening DevTools and inspecting the TextBlock causes it to redraw properly, showing all three lines.

cibuild0006806

@Gillibald Gillibald self-assigned this Apr 25, 2020
@mat1jaczyyy
Copy link
Contributor Author

mat1jaczyyy commented May 3, 2020

I can't access cibuilds prior to 6492, but I have 6151 and 6395 cached locally. The example provided works properly on 6151, but not 6395, so it was broken sometime in between those builds.

@Gillibald
Copy link
Contributor

Gillibald commented May 3, 2020

Can't repro this on current master
MultiLine

<StackPanel>
      <TextBox x:Name="txtBox" AcceptsReturn="True" Text="Hello"/>
      <TextBlock Background="Green" Text="{Binding #txtBox.Text}"/>
/StackPanel>

@mat1jaczyyy
Copy link
Contributor Author

@Gillibald for now you can repro from mat1jaczyyy/apollo-studio master, I had just reverted the cibuild I'm using to 6058 (where bug doesn't repro) but you should be able to get it just by upgrading Avalonia version. Steps:

  1. On the main SplashWindow, open the PreferencesWindow by clicking the gear icon in the top left
  2. In the Theme selection segment, select either Dark or Light (change the option) and multiline text saying "You must restart to apply changes" will appear next to it.

I know this kind of repro might be too much to ask for, so I'll try to make a minimal repro later today...

@Gillibald
Copy link
Contributor

Latest build has the number 7054

@mat1jaczyyy
Copy link
Contributor Author

@Gillibald I isolated the problem and turns out it's quite a specific setup. Hopefully this should get you a minimal repro of this
Repro3825.zip

@Gillibald
Copy link
Contributor

Thanks. Will have a look.

@Gillibald
Copy link
Contributor

This is a bug with the Grid I think and not related to the TextBlock.

This works:

<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto, Auto">
      <StackPanel Grid.Column="0">
        <TextBlock Text="Needed short" />
        <RadioButton Click="Trigger">Repro Bug</RadioButton>
      </StackPanel>

      <TextBlock Grid.Column="1" x:Name="Problem" Text="Original" />

      <TextBlock Grid.Row="1" Text="This text also needs to be long" />
    </Grid>

@mat1jaczyyy
Copy link
Contributor Author

Resizing the window immediately properly redraws and bug is gone

@Deadpikle
Copy link
Contributor

I am also experiencing something very similar, but in a UserControl that is presented via ContentControl. The ContentControl is in a Grid, but my actual UserControl has no Grid inside of it. Resizing the window causes the TextBlock to redraw properly, so I'm guessing that the above repro demonstrates the same bug I am getting.

I am working around this right now by:

MyProp = "";
MyProp = "real value";

@Gillibald
Copy link
Contributor

When you add a TextBlock that is bound to Bounds.Height of the affected TextBlock does the height change?

@Deadpikle
Copy link
Contributor

Deadpikle commented May 5, 2020

No, the height does not change. I can see that visually, too -- I have a really long string (directory) and just the last folder part should be changing.

I did a test, and if the height changes, the TextBlock updates properly. I tested this by doing:

MyProp += "a";

then spam-clicking my button. As soon as the height changed, the UI updated.

(Sorry, no repro right now. Tried to pull this out to a repro sample and that "fixed" it for some reason...not sure why atm.)

@Gillibald
Copy link
Contributor

I have an idea what is happening. Will rework the invalidation a bit and hopefully it fixes your issue.

@VisualMelon
Copy link
Contributor

I've been beating my head against this this afternoon with version 0.10.0-preview2. I only have problem when the background is null, so I can address my concern by making the background explicitly transparent. Looking through the sources, I can't work out what is going on, but I'll have another look tomorrow.

@VisualMelon
Copy link
Contributor

As best I can tell, the issue is with the constructor of GlythRunNode: it doesn't offset the draw operation Bounds based on the position. You can get a similar effect if you modify TextBlock to render the text offset somewhat.

I think this can be solved by just changing the constructor to take into account the baseline origin and ascent, i.e. change

: base(glyphRun.Bounds, transform)

to

        : base(new Rect(baselineOrigin.X + glyphRun.Bounds.X, baselineOrigin.Y + glyphRun.GlyphTypeface.Ascent * glyphRun.Scale + glyphRun.Bounds.Y, glyphRun.Bounds.Width, glyphRun.Bounds.Height), transform)

Adding a non-null background resolves the issue because the dirty rect includes its (correct) bounds.

I'd be happy to put a PR together if it helps.

@Gillibald
Copy link
Contributor

I don't see how this can be true. The GlyphRun's bounds don't originate at the baseline

@VisualMelon
Copy link
Contributor

VisualMelon commented Aug 19, 2020

@Gillibald GlyphRun.Bounds always starts at 0, 0, i.e. they don't know where they are to be rendered. The baselineOrigin then depends on the requested position and the ascent/descent etc.

This resolved the issue in my testing, which I traced back to the clipping rectangle being too small, and all GlythRunNode having the same Bounds origin, independent of which 'line' of text it was meant to be. The effect is that every line was occupying the same vertical space as far as the dirty rectangle is concerned.

@Gillibald
Copy link
Contributor

The correct fix is to create the bounds with new Rect(0, -ascent, width, height);

@VisualMelon
Copy link
Contributor

I agree that would make sense for handling the ascent.

@Gillibald
Copy link
Contributor

@Gillibald
Copy link
Contributor

Can be changed to

return new Rect(0, GlyphTypeface.Ascent * Scale, width, height);

@Gillibald
Copy link
Contributor

If you want you can test that fix and submit a PR.

@Gillibald
Copy link
Contributor

Just thinking about my proposed fix and it turns out I was wrong. GlyphRun's bounds should not care about the baseline origin. You were on the right track.

I think this might work:
https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Rendering/SceneGraph/GlyphRunNode.cs#L28
: base(glyphRun.Bounds.Translate(new Vector(baselineOrigin.X, -baselineOrigin.Y)), transform)

@VisualMelon VisualMelon mentioned this issue Aug 19, 2020
3 tasks
@VisualMelon
Copy link
Contributor

VisualMelon commented Aug 19, 2020

@Gillibald I think you are right that ascent should be handled by GlyphRun, but it needs to be done in CalculateBounds (see #4517)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants