当 DataGrid 嵌套在分组的 DataGrid 中时,相对列宽不起作用
Relative Column Widths Not Working When DataGrid is Nested Inside A Grouped DataGrid
假设我有一个具有 6 个属性的对象:
public class MyClass
{
public string Attribute1 { get; set; }
public string Attribute2 { get; set; }
public string Attribute3 { get; set; }
public string Attribute4 { get; set; }
public string Attribute5 { get; set; }
public string Attribute6 { get; set; }
}
我在 DataGrid 中显示这些对象的集合:
<Grid>
<DataGrid x:Name="myGrid" Margin="5, 5, 5, 5" AutoGenerateColumns="False" CanUserAddRows="False" IsReadOnly="True">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute1" Binding="{Binding Attribute1}" Width="5*"/>
<DataGridTextColumn Header="Attribute2" Binding="{Binding Attribute2}" Width="5*"/>
<DataGridTextColumn Header="Attribute3" Binding="{Binding Attribute3}" Width="10*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
我这样填充我的网格,按 "Attribute1"...
分组
public MainWindow()
{
InitializeComponent();
ObservableCollection<MyClass> data = new ObservableCollection<MyClass>();
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Circle", Attribute5 = "Large", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Square", Attribute5 = "Medium", Attribute6 = "Opaque" });
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Triangle", Attribute5 = "Large", Attribute6 = "Opaque" });
data.Add(new MyClass { Attribute1 = "Yellow", Attribute4 = "Square", Attribute5 = "Large", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Blue", Attribute4 = "Triangle", Attribute5 = "Small", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Blue", Attribute4 = "Sphere", Attribute5 = "Small", Attribute6 = "Opaque" });
ListCollectionView lcv = new ListCollectionView(data);
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Attribute1"));
myGrid.ItemsSource = lcv;
}
我设计了 GroupItems 的样式以在扩展器中显示嵌套的 DataGrid:
<Window.Resources>
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Foreground="Black">
<Expander.Header>
<TextBlock Foreground="Black" Text="{Binding Name}"/>
</Expander.Header>
<DockPanel>
<DataGrid ItemsSource="{Binding Items}" x:Name="subGrid" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute 4" Binding="{Binding Attribute4}" Width="Auto"/>
<DataGridTextColumn Header="Attribute 5" Binding="{Binding Attribute5}" Width="Auto"/>
<DataGridTextColumn Header="Attribute 6" Binding="{Binding Attribute6}" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
将我的嵌套 DataGrid 列宽设置为 "Auto"...效果很好:
问题是当我尝试使用相对宽度时...
<DataGrid ItemsSource="{Binding Items}" x:Name="subGrid" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute 4" Binding="{Binding Attribute4}" Width="1*"/>
<DataGridTextColumn Header="Attribute 5" Binding="{Binding Attribute5}" Width="1*"/>
<DataGridTextColumn Header="Attribute 6" Binding="{Binding Attribute6}" Width="2*"/>
</DataGrid.Columns>
</DataGrid>
现在看起来是这样的...
不仅列超级瘦...它们不能像往常一样用鼠标调整大小。
这个问题真是让我百思不得其解。我搜索了 SO 并尝试了几个有点相关的问题,但没有任何运气。
如何将嵌套 DataGrid 上的列设置为使用相对宽度?
我认为问题在于 WPF 不知道 DockPanel 的宽度,所以您得到那些细长的列。
一种解决方案是将 DockPanel(或 DataGrid)的宽度设置为固定宽度,例如 500 像素。
另一个解决方案是将DataGrid 的Width 绑定到DockPanel 的ActualWidth。这行得通,但 DataGrid 的大小只会增加,当 window 变小时它不会缩小。
<DataGrid ItemsSource="{Binding Items}"
x:Name="subGrid"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserAddRows="False"
Width="{Binding
RelativeSource={RelativeSource AncestorType=DockPanel}, Path=ActualWidth}">
另一种解决方案是将 DockPanel 的宽度绑定到扩展器的实际宽度。这样做的问题是它不能正常工作……扩展器变大了,因为 DockPanel 变大了,我们进入了一个循环。我们真正想要的是 Expander 的 ActualWidth 减去足够的值,以免导致 Expander 增加其宽度。我做了一些实验,"ActualWidth - 3" 似乎有效(但我不知道为什么是 3...)。如果添加 Paddings 或 Margins,这 3 个可能需要改变。要将其放入绑定中,我们需要一个 IValueConverter。
public class ActualWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double)
return (double)value - 3;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
您需要将转换器添加为资源(应用程序或 Window 或其他):
<Window ....
xmlns:app="clr-namespace:WpfApplication25">
<Window.Resources>
<app:ActualWidthConverter x:Key="ActualWidthConverter" />
</Window.Resources>
当然,您需要将绑定应用于 DockPanel 的宽度:
<DockPanel Width="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=ActualWidth, Converter={StaticResource ActualWidthConverter}}">
这不是一个完美的解决方案,但也许会有帮助?此方法的替代版本可以使用 MultiBinding;传入 Expander 的 ActualWidth 和 DockPanel 的 Margin:ActualWidth - Margin.Left - Margin.Right - 3(我还在想为什么是 3?其他人的电脑上也会是 3 吗?)
假设我有一个具有 6 个属性的对象:
public class MyClass
{
public string Attribute1 { get; set; }
public string Attribute2 { get; set; }
public string Attribute3 { get; set; }
public string Attribute4 { get; set; }
public string Attribute5 { get; set; }
public string Attribute6 { get; set; }
}
我在 DataGrid 中显示这些对象的集合:
<Grid>
<DataGrid x:Name="myGrid" Margin="5, 5, 5, 5" AutoGenerateColumns="False" CanUserAddRows="False" IsReadOnly="True">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute1" Binding="{Binding Attribute1}" Width="5*"/>
<DataGridTextColumn Header="Attribute2" Binding="{Binding Attribute2}" Width="5*"/>
<DataGridTextColumn Header="Attribute3" Binding="{Binding Attribute3}" Width="10*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
我这样填充我的网格,按 "Attribute1"...
分组 public MainWindow()
{
InitializeComponent();
ObservableCollection<MyClass> data = new ObservableCollection<MyClass>();
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Circle", Attribute5 = "Large", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Square", Attribute5 = "Medium", Attribute6 = "Opaque" });
data.Add(new MyClass { Attribute1 = "Red", Attribute4 = "Triangle", Attribute5 = "Large", Attribute6 = "Opaque" });
data.Add(new MyClass { Attribute1 = "Yellow", Attribute4 = "Square", Attribute5 = "Large", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Blue", Attribute4 = "Triangle", Attribute5 = "Small", Attribute6 = "Transparent" });
data.Add(new MyClass { Attribute1 = "Blue", Attribute4 = "Sphere", Attribute5 = "Small", Attribute6 = "Opaque" });
ListCollectionView lcv = new ListCollectionView(data);
lcv.GroupDescriptions.Add(new PropertyGroupDescription("Attribute1"));
myGrid.ItemsSource = lcv;
}
我设计了 GroupItems 的样式以在扩展器中显示嵌套的 DataGrid:
<Window.Resources>
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Foreground="Black">
<Expander.Header>
<TextBlock Foreground="Black" Text="{Binding Name}"/>
</Expander.Header>
<DockPanel>
<DataGrid ItemsSource="{Binding Items}" x:Name="subGrid" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute 4" Binding="{Binding Attribute4}" Width="Auto"/>
<DataGridTextColumn Header="Attribute 5" Binding="{Binding Attribute5}" Width="Auto"/>
<DataGridTextColumn Header="Attribute 6" Binding="{Binding Attribute6}" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
将我的嵌套 DataGrid 列宽设置为 "Auto"...效果很好:
问题是当我尝试使用相对宽度时...
<DataGrid ItemsSource="{Binding Items}" x:Name="subGrid" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Attribute 4" Binding="{Binding Attribute4}" Width="1*"/>
<DataGridTextColumn Header="Attribute 5" Binding="{Binding Attribute5}" Width="1*"/>
<DataGridTextColumn Header="Attribute 6" Binding="{Binding Attribute6}" Width="2*"/>
</DataGrid.Columns>
</DataGrid>
现在看起来是这样的...
不仅列超级瘦...它们不能像往常一样用鼠标调整大小。
这个问题真是让我百思不得其解。我搜索了 SO 并尝试了几个有点相关的问题,但没有任何运气。
如何将嵌套 DataGrid 上的列设置为使用相对宽度?
我认为问题在于 WPF 不知道 DockPanel 的宽度,所以您得到那些细长的列。
一种解决方案是将 DockPanel(或 DataGrid)的宽度设置为固定宽度,例如 500 像素。
另一个解决方案是将DataGrid 的Width 绑定到DockPanel 的ActualWidth。这行得通,但 DataGrid 的大小只会增加,当 window 变小时它不会缩小。
<DataGrid ItemsSource="{Binding Items}"
x:Name="subGrid"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserAddRows="False"
Width="{Binding
RelativeSource={RelativeSource AncestorType=DockPanel}, Path=ActualWidth}">
另一种解决方案是将 DockPanel 的宽度绑定到扩展器的实际宽度。这样做的问题是它不能正常工作……扩展器变大了,因为 DockPanel 变大了,我们进入了一个循环。我们真正想要的是 Expander 的 ActualWidth 减去足够的值,以免导致 Expander 增加其宽度。我做了一些实验,"ActualWidth - 3" 似乎有效(但我不知道为什么是 3...)。如果添加 Paddings 或 Margins,这 3 个可能需要改变。要将其放入绑定中,我们需要一个 IValueConverter。
public class ActualWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double)
return (double)value - 3;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
您需要将转换器添加为资源(应用程序或 Window 或其他):
<Window ....
xmlns:app="clr-namespace:WpfApplication25">
<Window.Resources>
<app:ActualWidthConverter x:Key="ActualWidthConverter" />
</Window.Resources>
当然,您需要将绑定应用于 DockPanel 的宽度:
<DockPanel Width="{Binding RelativeSource={RelativeSource AncestorType=Expander}, Path=ActualWidth, Converter={StaticResource ActualWidthConverter}}">
这不是一个完美的解决方案,但也许会有帮助?此方法的替代版本可以使用 MultiBinding;传入 Expander 的 ActualWidth 和 DockPanel 的 Margin:ActualWidth - Margin.Left - Margin.Right - 3(我还在想为什么是 3?其他人的电脑上也会是 3 吗?)