WPF ContentControl 宽度会增加,但在包裹在 ScrollViewer 中时不会缩小

Posted

技术标签:

【中文标题】WPF ContentControl 宽度会增加,但在包裹在 ScrollViewer 中时不会缩小【英文标题】:WPF ContentControl width grows but doesn't shrink when wrapped in a ScrollViewer 【发布时间】:2014-02-14 15:03:08 【问题描述】:

我试图弄清楚如何让我的ContentControl 正确地水平滚动(目前垂直滚动很好)。正确地说,我的意思是我希望看到要拉伸(无限扩展)的内容,同时具有滚动条出现的最小尺寸,以便内容不会在ContentControl 的区域后面溢出,所以这里有一个快速介绍:

主窗口的结构如下:

网格(2 列 .3* 和 .7*) 边框 网格(7 行,一组设置为 * ContentControl 所在的位置) 带有 StackPanel 的 ScrollViewer(纯粹用于测试)包装了具有 Auto Width 的 ContentControl

ContentControl的模板:

网格(宽度设置为 UserControl 的 ActualWidth,6 行,其中一个设置为 Auto,其中 ItemsControl 去 ItemsControl 描述了 DataTemplate 类型的 ItemTemplate,其中包含一个网格,其中我有一个 DataGrid

实际的问题是 ContentControl 会随着您调整窗口大小而增长,但不会随着窗口大小调整而缩小。

主视图 XAML(为清楚起见已截断):

<ScrollViewer Grid.Row="5" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <ContentControl Grid.Row="5" Background="Transparent"  Focusable="False" Margin="0,5,0,0"
                            Content="Binding CurrentSection" ContentTemplateSelector="StaticResource templateSelector/>
</ScrollViewer>

Tempate XAML(为清楚起见截断):

<Grid>
...
    <ItemsControl Grid.Row="4" ItemsSource="Binding Data.QualifyingDistributionsDividends" x:Name="QualifyingItemsControl">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="DTLayoutGrid">
                    ...
                    <Grid Grid.Row="1" x:Name="DataLayout" Width="Binding ElementName=DTLayoutGrid, Path=ActualWidth" HorizontalAlignment="Stretch">
                        ...
                        <DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="8" HorizontalScrollBarVisibility="Disabled"
                                  ItemsSource="Binding Payments" Style="StaticResource DataGridStyle" CellStyle="StaticResource DataGridNormalCellStyle">
                        </DataGrid>
                    </Grid>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

那么会发生什么? Datagrid 假定整个 DataTemplate 的宽度(以及它的底层控件设置为 DataTemplates 大小,然后 * 列假定所有空白空间。当您尝试调整包含此代码的整个窗口的大小时,它将正确增长, 扩展 * 列,但它似乎没有“注册”收缩,它保持你扩展它的大小,在上面应用滚动条并忘记它。

到目前为止,我尝试的是为 ItemsControl 设置宽度,它的底层父级如 Grid 等,还将大小设置为 ContentControlStackPanelScrollViewer 和父级 Grid。 我还尝试在Datagrid 上直接使用scrollviewers,这会产生癫痫“每秒调整一百万”的场景。我也玩过HorizontalAlignments 在某些情况下,我确实设法让水平滚动条正确显示,但不幸的是,这使我的DataGrid 的 * 列假设Auto 宽度而不是Star 所以DataGrid 开始在右侧有一个空白区域(不幸的是无法接受...)

我知道为了让水平滚动条工作,滚动查看器的父级或子级需要设置宽度,我想我无法确定我需要在哪里限制它。 DataGrids 需要随着主窗口无限扩展,同时让第一列填满所有可用空间。 如果您需要这方面的更多信息,请立即告诉我,我会很乐意回答。

【问题讨论】:

将 Grid 的宽度提供给 ContentControl 会做出正确的反应,但是一旦达到最小尺寸,模板就会溢出并且不会出现滚动条,给它一个 HorizontalAlignment="Stretch" 什么都不做,删除 ScrollViewer.CanContentScroll="False" 也是如此 老兄……这太长了……我们不需要你的生活史,只需要relevant part of your program。 如何详细解释一个问题,以便人们更好地理解它的生活故事?由于未知问题的来源,必须放入大量代码。我想我会削减 sn-ps... 原谅我的措辞...我只是给你很好的建议来帮助你回答你的问题。这里的许多用户会看到您的问题持续了多长时间,然后简单地转到下一个问题。 +1 虽然做得更简洁,但做得很好。 别担心!我在想这不是一件容易的事,所以决定详细说明这个场景。 【参考方案1】:

在我看来,这只是另一个可怕的StackPanel 布局问题的案例。这个问题一次又一次地出现,我承认我在开始学习 WPF 时遇到了同样的问题。 StackPanel 确实考虑其父级的可用大小,而其他Panels,例如DockPanelGrid(是的,这实际上也是Panel)做。

在 MSDN 的How to: Choose Between StackPanel and DockPanel 页面中有解释:

虽然您可以使用 DockPanel 或 StackPanel 来堆叠子元素,但这两个控件并不总是产生相同的结果。例如,放置子元素的顺序会影响 DockPanel 中子元素的大小,但不会影响 StackPanel 中的大小。出现这种不同的行为是因为 StackPanel 在 Double.PositiveInfinity 的堆叠方向上测量;但是,DockPanel 仅测量可用大小。

StackPanel 只应真正用于对齐多个项目,例如Buttons 或其他控件,可用空间不是问题。所以无论如何,解决方案应该很简单......只需从ScrollViewer中删除StackPanel。无论如何,它似乎没有任何用途。


更新>>>

再看一遍,你的意思好像是问题出在内部DataTemplate,对吧?您可能可以通过将ItemsControl.HorizontalContentAlignment 属性设置为Stretch 来解决此问题。这将确保每个项目都保持在ItemsControl 的边界内。

我还将删除您在 Grid.Width 上的 Binding,因为您不需要它...默认情况下,子 Grid 将占用父 Grid 的全部空间。如果这些想法不起作用,只需简化您的问题。说真的,如果您遵循我在 cmets 中提供的帮助中心链接页面中的建议,那么您将解决问题,或者能够回到这里并提供一个完整但简洁的示例,我们可以测试。

【讨论】:

是的,我已经添加了stackpanel作为测试,用一个网格替换它似乎有相似的结果,但略有不同,ScrollBar 出现时最多有1个像素,不幸的是没有能够缩小ContentControl 问题仍然存在。删除它与在那里拥有Grid 没有区别。还没有尝试过DockPanel,因为我个人避免使用它,但我还是会试一试。睡一觉后我会尝试制作一个小重现应用程序,看看这是否会更有意义,也许这会更准确地查明问题出在哪里 问题是Grid.Width。不幸的是,删除它会使Datagrids 中的所有Star 列都采用自动大小,这是我首先尝试解决的问题,因为第一列需要假设所有可用的屏幕空间。 我已经剥离了所有内容并了解到这只是一个典型问题,即如果存在任何 Star Width 列,则 ScrollViewer 元素内的 DataGrids 将无法正确运行。这就是Grid.Width 被设置成这种方式的原因。我已经尝试了很多不同的解决方法,但都无济于事,我会继续寻找更多 似乎***.com/a/20120082/3008444 和在Datagrid 周围使用边框的类似方法会产生同样的问题,无论它是在ContentControl 的内部还是外部 ***.com/a/17876732/3008444 看起来 mardok 也有同样的问题,无法收缩。【参考方案2】:

我通过使用UniformGrid 作为ItemsPanel 找到了我正在寻找的行为,它的行绑定到ItemsSource 模型的计数:

<ScrollViewer>
    <ItemsControl ItemsSource="Binding MyCollection">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Rows="Binding MyCollection.Count" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                 ...                      
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

正如@Sheridan 上面指出的那样,StackPanel 似乎正在造成麻烦。另外,感谢https://***.com/a/23375262/385273 指出UniformGrid 选项。

【讨论】:

以上是关于WPF ContentControl 宽度会增加,但在包裹在 ScrollViewer 中时不会缩小的主要内容,如果未能解决你的问题,请参考以下文章

WPF - 将 ContentControl 添加到自定义画布

[WPF自定义控件]从ContentControl开始入门自定义控件

带有 DataTemplate 的 ContentControl 不显示任何内容(WPF MVVM)

使用 ContentControl 在 WPF 中显示视图不起作用

c#WPF删除contentcontrol

TabControl 内的 WPF ContentControl 不显示 DataTemplates