C# WPF - 使 DataGrid 拉伸到可用大小,而不是扩展可用大小
C# WPF - Make DataGrid stretch to available size, not expand the available size
我使用 Visual Studio 2010。我一直在努力获取数据网格来填充现有的 space。如有必要,在数据网格上显示滚动条,而不是在页面上。
示例代码:
<Page x:Class="TestApp.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<StackPanel>
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</StackPanel>
</Viewbox>
</Expander>
</Grid>
问题是,似乎无论我做什么,数据网格都会一直伸展直到所有列都完全可见,即使它伸展超过 window(或页面)大小。
注意:我在右侧有一个面板,显示状态、日期、信息...,这些应该保留在屏幕上。
我尝试了太多东西,无法一一列举。我发现唯一可行的 'solution' 是在网格上添加另一个控件(不可见),如分隔符,并将扩展器宽度绑定到分隔符的宽度。它有效,但它是蹩脚的编程。
MaxWidth="{Binding ElementName=MySeparator, Path=ActualWidth}"
将堆栈面板的宽度绑定到列的(实际)宽度只会使堆栈面板消失。
有人可以帮助我吗?谢谢。
-- 更新--
这就是我想要实现的目标:
看来如果我使用硬编码的列宽,就不会出现这个问题。仅当有一个列具有 star-length 时,数据网格才需要多少 space。
尝试像这样用 ScrollViewer
包裹你的 DataGrid
:
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid>
// SOME CONTENT
</DataGrid>
</ScrollViewer>
此外,我完全不知道您是否需要 ViewBox
。尝试删除它,看看它是否符合您的需求。
去掉 StackPanel
:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</Viewbox>
</Expander>
</Grid>
StackPanels
和 ScrollViewers
不能很好地协同工作,因为 StackPanel
测量其子项的方式:
并且由于 DataGrid
的默认控件模板包含一个 ScrollViewer
,您无需添加自己的模板。
由于你的图表只解决了滚动问题,所以我现在主要关注它。我仍然不完全清楚您希望此布局如何显示 before 需要滚动,但让我们以此为起点。试一试,如果行为不是您想要的,请尝试尽可能具体地说明需要更改的内容(一张图片胜过一千个字)。
为简洁起见,我只包含 Expander
及其内容。祖先元素与原始元素完全相同 post.
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<StackPanel>
<DataGrid Margin="5"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<!-- Temporary items source to demonstrate grid measuring to fit rows -->
<DataGrid.ItemsSource>
<x:Array Type="s:String">
<s:String>Dummy Row 1</s:String>
<s:String>Dummy Row 2</s:String>
<s:String>Dummy Row 3</s:String>
</x:Array>
</DataGrid.ItemsSource>
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn" />
<DataGridTextColumn Header="MySecondColumn" />
<DataGridTextColumn Header="MyThirdColumn" />
<DataGridTextColumn Header="MyFourthColumn" />
<DataGridTextColumn Header="MyFifthColumn" />
<DataGridTextColumn Header="MySixthColumn" />
<DataGridTextColumn Header="MySeventhColumn" />
<DataGridTextColumn Header="MyEighthColumn" />
<DataGridTextColumn Header="MyNinthColumn" />
<DataGridTextColumn Header="MyTenthColumn" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click" />
</StackPanel>
</Expander>
这是两列的样子:
[
这是十列的样子:
更新
根据您对另一个答案的评论,您的页面在运行时加载到 ScrollViewer
中。如果 ScrollViewer
支持水平滚动,那么这就是问题的根源:它会根据需要为您的页面提供尽可能多的水平 space,而这种需求是由 DataGrid
驱动的.一个(hacky)解决方法是将您的 DataGrid
包裹在一个自定义装饰器中,该装饰器在测量时伪造其所需的宽度,然后在排列时填充任何可用的水平 space 。如果你想试试这个,使用我上面的例子,但是把 DataGrid
包装在装饰器里,像这样:
<l:ZeroWidthDecorator xmlns:l="clr-namespace:TestApp">
<DataGrid><!-- ... --></DataGrid>
</l:ZeroWidthDecorator>
装饰器的代码如下:
public class ZeroWidthDecorator : Border
{
private Size _lastSize;
private Size _idealSize;
protected override void OnVisualChildrenChanged(DependencyObject added, DependencyObject removed)
{
base.OnVisualChildrenChanged(added, removed);
_idealSize = new Size();
_lastSize = new Size();
}
protected override Size MeasureOverride(Size constraint)
{
var child = this.Child;
if (child == null)
return new Size();
if (child.IsMeasureValid)
child.Measure(new Size(_lastSize.Width, Math.Max(_lastSize.Height, constraint.Height)));
else
child.Measure(new Size(0d, constraint.Height));
_idealSize = child.DesiredSize;
return new Size(0d, _idealSize.Height);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
var child = this.Child;
if (child != null)
{
if (arrangeSize != _lastSize)
{
// Our parent will assume our measure is the same if the last
// arrange bounds are still available, so force a reevaluation.
this.InvalidateMeasure();
}
child.Arrange(new Rect(arrangeSize));
}
_lastSize = arrangeSize;
return arrangeSize;
}
}
我没有对此进行过广泛的测试,但我尝试了几种不同的方案,似乎 有效。 使用它需要您自担风险。
感谢大家的努力。该解决方案由 Mike Strobel 在评论中提出。由于我无法将评论标记为,因此我将在此处重复。
我有一个 window,包含一个滚动查看器,所有页面都放在上面。我从 window 中删除了滚动查看器并将滚动条放在页面上。
<Page x:Class=...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<Grid>
这样真的解决了问题!谢谢迈克!
(如果你也运行遇到这个问题,请也给mike的评论点个赞)。
我使用 Visual Studio 2010。我一直在努力获取数据网格来填充现有的 space。如有必要,在数据网格上显示滚动条,而不是在页面上。
示例代码:
<Page x:Class="TestApp.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<StackPanel>
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</StackPanel>
</Viewbox>
</Expander>
</Grid>
问题是,似乎无论我做什么,数据网格都会一直伸展直到所有列都完全可见,即使它伸展超过 window(或页面)大小。 注意:我在右侧有一个面板,显示状态、日期、信息...,这些应该保留在屏幕上。
我尝试了太多东西,无法一一列举。我发现唯一可行的 'solution' 是在网格上添加另一个控件(不可见),如分隔符,并将扩展器宽度绑定到分隔符的宽度。它有效,但它是蹩脚的编程。
MaxWidth="{Binding ElementName=MySeparator, Path=ActualWidth}"
将堆栈面板的宽度绑定到列的(实际)宽度只会使堆栈面板消失。
有人可以帮助我吗?谢谢。
-- 更新--
这就是我想要实现的目标:
看来如果我使用硬编码的列宽,就不会出现这个问题。仅当有一个列具有 star-length 时,数据网格才需要多少 space。
尝试像这样用 ScrollViewer
包裹你的 DataGrid
:
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid>
// SOME CONTENT
</DataGrid>
</ScrollViewer>
此外,我完全不知道您是否需要 ViewBox
。尝试删除它,看看它是否符合您的需求。
去掉 StackPanel
:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<Viewbox Stretch="Uniform">
<DataGrid Margin="5"
Height="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn"/>
<DataGridTextColumn Header="MySecondColumn"/>
<DataGridTextColumn Header="MyThirdColumn"/>
<DataGridTextColumn Header="MyFourthColumn"/>
<DataGridTextColumn Header="MyFifthColumn"/>
<DataGridTextColumn Header="MySixthColumn"/>
<DataGridTextColumn Header="MySeventhColumn"/>
<DataGridTextColumn Header="MyEighthColumn"/>
<DataGridTextColumn Header="MyNinthColumn"/>
<DataGridTextColumn Header="MyTenthColumn"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click"/>
</Viewbox>
</Expander>
</Grid>
StackPanels
和 ScrollViewers
不能很好地协同工作,因为 StackPanel
测量其子项的方式:
并且由于 DataGrid
的默认控件模板包含一个 ScrollViewer
,您无需添加自己的模板。
由于你的图表只解决了滚动问题,所以我现在主要关注它。我仍然不完全清楚您希望此布局如何显示 before 需要滚动,但让我们以此为起点。试一试,如果行为不是您想要的,请尝试尽可能具体地说明需要更改的内容(一张图片胜过一千个字)。
为简洁起见,我只包含 Expander
及其内容。祖先元素与原始元素完全相同 post.
<Expander x:Name="MyExpander"
Grid.Column="1"
Grid.Row="1"
VerticalAlignment="Top"
Header="My Expander"
Expanded="MyExpander_Expanded"
Collapsed="MyExpander_Collapsed">
<StackPanel>
<DataGrid Margin="5"
xmlns:s="clr-namespace:System;assembly=mscorlib">
<!-- Temporary items source to demonstrate grid measuring to fit rows -->
<DataGrid.ItemsSource>
<x:Array Type="s:String">
<s:String>Dummy Row 1</s:String>
<s:String>Dummy Row 2</s:String>
<s:String>Dummy Row 3</s:String>
</x:Array>
</DataGrid.ItemsSource>
<DataGrid.Columns>
<DataGridTextColumn Header="MyFirstColumn" />
<DataGridTextColumn Header="MySecondColumn" />
<DataGridTextColumn Header="MyThirdColumn" />
<DataGridTextColumn Header="MyFourthColumn" />
<DataGridTextColumn Header="MyFifthColumn" />
<DataGridTextColumn Header="MySixthColumn" />
<DataGridTextColumn Header="MySeventhColumn" />
<DataGridTextColumn Header="MyEighthColumn" />
<DataGridTextColumn Header="MyNinthColumn" />
<DataGridTextColumn Header="MyTenthColumn" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="DoSomething"
Margin="5"
Width="100"
Height="30"
Content="Do Something"
Click="DoSomething_Click" />
</StackPanel>
</Expander>
这是两列的样子:
[
这是十列的样子:
更新
根据您对另一个答案的评论,您的页面在运行时加载到 ScrollViewer
中。如果 ScrollViewer
支持水平滚动,那么这就是问题的根源:它会根据需要为您的页面提供尽可能多的水平 space,而这种需求是由 DataGrid
驱动的.一个(hacky)解决方法是将您的 DataGrid
包裹在一个自定义装饰器中,该装饰器在测量时伪造其所需的宽度,然后在排列时填充任何可用的水平 space 。如果你想试试这个,使用我上面的例子,但是把 DataGrid
包装在装饰器里,像这样:
<l:ZeroWidthDecorator xmlns:l="clr-namespace:TestApp">
<DataGrid><!-- ... --></DataGrid>
</l:ZeroWidthDecorator>
装饰器的代码如下:
public class ZeroWidthDecorator : Border
{
private Size _lastSize;
private Size _idealSize;
protected override void OnVisualChildrenChanged(DependencyObject added, DependencyObject removed)
{
base.OnVisualChildrenChanged(added, removed);
_idealSize = new Size();
_lastSize = new Size();
}
protected override Size MeasureOverride(Size constraint)
{
var child = this.Child;
if (child == null)
return new Size();
if (child.IsMeasureValid)
child.Measure(new Size(_lastSize.Width, Math.Max(_lastSize.Height, constraint.Height)));
else
child.Measure(new Size(0d, constraint.Height));
_idealSize = child.DesiredSize;
return new Size(0d, _idealSize.Height);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
var child = this.Child;
if (child != null)
{
if (arrangeSize != _lastSize)
{
// Our parent will assume our measure is the same if the last
// arrange bounds are still available, so force a reevaluation.
this.InvalidateMeasure();
}
child.Arrange(new Rect(arrangeSize));
}
_lastSize = arrangeSize;
return arrangeSize;
}
}
我没有对此进行过广泛的测试,但我尝试了几种不同的方案,似乎 有效。 使用它需要您自担风险。
感谢大家的努力。该解决方案由 Mike Strobel 在评论中提出。由于我无法将评论标记为,因此我将在此处重复。
我有一个 window,包含一个滚动查看器,所有页面都放在上面。我从 window 中删除了滚动查看器并将滚动条放在页面上。
<Page x:Class=...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<Grid>
这样真的解决了问题!谢谢迈克!
(如果你也运行遇到这个问题,请也给mike的评论点个赞)。