水平虚线拉伸到容器宽度

10

我有一个布局包含在 ScrollViewer 中,我需要画一条横跨整个容器的水平虚线。 我最接近的方法如下:

<ScrollViewer HorizontalScrollBarVisibility="Auto">
    <StackPanel>
        <Button Width="400" Height="50" VerticalAlignment="Top" Margin="10" />
        <Line HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Stroke="Black"
              X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"
              StrokeDashArray="2 2" StrokeThickness="1" />
    </StackPanel>
</ScrollViewer>

示例外观良好

这个方案几乎可行,但是一旦容器(在我的情况下是窗口)被放大,当容器重新调整大小时,该行不会恢复到适当的大小。以下是我横向调整窗口大小后相同窗口的屏幕截图。

增加和减少窗口大小后的示例屏幕截图

请注意,虚线是重要的,因为它意味着涉及拉伸线条的解决方案不起作用(虚线看起来被拉伸了)。

我知道这是由于X2 =“{Binding ActualWidth,RelativeSource = {RelativeSource Self}}”绑定造成的(设计上,该线始终是可滚动区域中最宽的东西,因此当我将窗口缩小滚动区域时,该线定义了滚动区域的宽度),但我想不出解决办法。

我该如何解决这个问题?


为什么使用ViewportWidth不起作用的屏幕截图

为什么使用ViewportWidth不起作用的屏幕截图


你能否把MainWindow的完整xaml代码(显示ViewportWidth无效)发布到pastebin上?因为我已经编译了我的代码,调整了窗口大小,但没有出现问题。 - lisp
1
@lisp 这只是一个标准的窗口 - 你需要调整窗口大小(使滚动条出现)然后向右滚动。 - Justin
可以将多个绑定绑定到ScrollViewer的ViewportWidth和ContentHorizontalOffset之和,但与Clemens的解决方案相比,这样做会变得不必要复杂。 - lisp
3个回答

12
我意识到我需要的是在布局的测量步骤期间要求Line占用零空间,然后在排列步骤中使用所有可用的空间。我碰巧发现了这个问题Make WPF/SL grid ignore a child element when determining size,其中介绍了使用包含此逻辑的自定义装饰器的方法。
public class NoSizeDecorator : Decorator
{
    protected override Size MeasureOverride(Size constraint) {
        // Ask for no space
        Child.Measure(new Size(0,0));
        return new Size(0, 0);
    }        
}

我希望有一种现有的布局控件能够包含这个逻辑,以避免编写自己的布局逻辑。然而,这里的逻辑非常简单,所以我并不是太在意。然后修改的XAML如下:

<ScrollViewer HorizontalScrollBarVisibility="Auto">
    <StackPanel>
        <Button Width="400" Height="50" VerticalAlignment="Top" Margin="10" />
        <local:NoSizeDecorator Height="1">
            <Line Stroke="Black" HorizontalAlignment="Stretch"
                  X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"
                  StrokeDashArray="2 2" StrokeThickness="1" />
        </local:NoSizeDecorator>
    </StackPanel>
</ScrollViewer>

这个运作得非常完美。


3
我尝试在StackPanel中添加一条线,并只需使用[X2 = "{Binding ActualWidth,RelativeSource = {RelativeSource Self}}"],这样就能完美地工作。 - Cheung
在 UWP 应用程序中呢? - bunkerdive

8

如果你将Width设为零,并且将ClipToBounds设置为false,那么你可以在左对齐的画布中放置非常长的一行。

<ScrollViewer HorizontalScrollBarVisibility="Auto">
    <StackPanel>
        <Button Width="400" Height="50" VerticalAlignment="Top" Margin="10" />
        <Canvas HorizontalAlignment="Left" Width="0" ClipToBounds="False">
            <Line Stroke="Black" StrokeDashArray="2 2" X2="10000"/>
        </Canvas>
    </StackPanel>
</ScrollViewer>

我知道这个方法可以运行,但我希望有更优雅的解决方案——这种方法让我感觉像是在“hack”。 - Justin
1
实际上,您需要一个技巧。 ScrollViewer 旨在显示具有显式大小(独立于 ScrollViewer 的实际大小)的内容。 您希望拥有一些大小部分取决于 ScrollViewer 的实际大小的内容。 - Clemens
3
如果你觉得10000这个值看起来太过不自然,那么你可以这样绑定属性:X2="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}}" - Clemens
1
至少我的解决方案比你的少一个类和一个绑定 :-) - Clemens

0
你可以使用Path而不是Line。这会生成一条水平线,其大小适应容器的宽度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接