AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
26.1k stars 2.26k forks source link

Wrap position of TextBlock is strange in ScrollViewer with Padding. #8838

Open whistyun opened 2 years ago

whistyun commented 2 years ago

Describe the bug When displaying TextBlock on ScrollViewer which has padding, Last word displayed on the screen may be cut off.

To Reproduce

  1. Create MainWindow.axaml like the bellow.
    <Window ... >
       <ScrollViewer Padding="20">
           <TextBlock TextWrapping="Wrap" Text="The World Wide Web (WWW), commonly known as the Web, is an information system enabling documents and other web resources to be accessed over the Internet."/>
       </ScrollViewer>
    </Window>
  2. Show the window and shrink the window width to wrap text. Animation

Expected behavior Text wrap correctly and all characters are displayed on the screen.

Screenshots (Actual behavior) Last word displayed on the screen may be cut off. image

Desktop (please complete the following information):

Additional context Perhaps, ScrollViewer does not seem to take Padding into account when measuring size. I attempt to override ScrollViewer's MeasureOverride to deflate availableSize, and it seems to wrap correctrly.

image

Gillibald commented 2 years ago

If this fixes your issue this isn't an issue with text layout and instead the ScrollViewer isn't measuring children with the proper size.

jp2masa commented 2 years ago

This is probably related to #7889. The fix wasn't complete I guess, because ScrollContentPresenter does not handle Padding correctly. Looking at ContentPresenter:

https://github.com/AvaloniaUI/Avalonia/blob/0b01a51c9e83a779ea273277d9efc8a90e444fea/src/Avalonia.Controls/Presenters/ContentPresenter.cs#L592-L595

I think it would be enough to copy this logic to ScrollContentPresenter:

https://github.com/AvaloniaUI/Avalonia/blob/0b01a51c9e83a779ea273277d9efc8a90e444fea/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs#L271-L272

This could become:

var size = LayoutHelper.MeasureChild(Child, constraint, Padding, BorderThickness);
return size.Constrain(availableSize); 

Or maybe simply:

return base.MeasureOverride(constraint).Constrain(availableSize);

EDIT: Also just noticed that BorderThickness and BorderBrush are probably broken as well. They should be passed here with TemplateBindings:

https://github.com/AvaloniaUI/Avalonia/blob/0b01a51c9e83a779ea273277d9efc8a90e444fea/src/Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml#L27

ScrollContentPresenter already inherits Render from ContentPresenter, but ArrangeWithAnchoring doesn't seem to handle border nor padding, that probably needs to be fixed as well.

jonchardy commented 2 years ago

Yes, it seems ScrollViewer is not properly respecting padding in 11.0.0-preview1. I was about to report this, but it seems it's already being discussed here.

For reference:

To Reproduce

  1. In a standard template, use the following code in MainView.axaml:

    
    <UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="AvaloniaApp.Views.MainView">
    
    <DockPanel>
    <ScrollViewer Padding="3,3,20,20">
      <Panel Width="3000" Height="3000" Background="Red" />
    </ScrollViewer>
    </DockPanel>


2. Run the application.

**Expected behavior**
In 0.10.18, this renders as expected, with padding around the red Panel.

**Screenshots**
0.10.18
<img width="420" alt="image" src="https://user-images.githubusercontent.com/1202288/187466701-89b0e5d3-db59-47c5-9fb5-840a99d4ef15.png">

11.0.0-preview1
<img width="463" alt="image" src="https://user-images.githubusercontent.com/1202288/187467213-19c862cb-15f4-4630-bfee-808cbde34173.png">
jp2masa commented 2 years ago

I was trying to fix this and the current design is just broken I guess, there are 2 options:

  1. Fix ScrollContentPresenter to accept border and padding, which I was trying to do, but the real question is where do they apply? Viewport, extent, or some other way? What do they actually mean in a scroll presenter?
  2. Simply stop inheriting from ContentPresenter, which will make border and padding disappear, so they don't have to be handled.
Gillibald commented 2 years ago

I was trying to fix this and the current design is just broken I guess, there are 2 options:

  1. Fix ScrollContentPresenter to accept border and padding, which I was trying to do, but the real question is where do they apply? Viewport, extent, or some other way? What do they actually mean in a scroll presenter?
  2. Simply stop inheriting from ContentPresenter, which will make border and padding disappear, so they don't have to be handled.

Padding only applies to the Viewport

jp2masa commented 2 years ago

Something like this, where border is black, padding is orange, and content is white?

scroll

This is actually something that you can't achieve without handling border and padding on scroll viewer, but it doesn't seem to be a consistent UX: the scroll bar size and position no longer match the content bounds. Even with that problem, I believe this may be useful, but for how many people? Is it worth the effort?

When I originally "fixed" the padding I actually wanted the effect of having a border inside the scroll viewer, so I have no idea how useful this actually is.