如何 'wrap' WPF DataGrid 的列(而不是 text/content)?
How to 'wrap' the columns (not the text/content) of a WPF DataGrid?
我正在尝试实现一个可以 'wrap' WPF DataGrid 的解决方案 - 我的意思是整个列和行都换行,不是 他们的文字或内容(见下图)。
我有一组由列和行组成的数据(列 headers),我想在限制 window 的宽度限制时换行,而不是使用水平滚动表示数据显示的栏 off-screen.
我看过使用 WrapPanel 作为我的 DataGrid 的 ItemsPanelTemplate,但是我无法在此基础上进一步实现我想要的。
<DataGrid.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</DataGrid.ItemsPanel>
如果有一个答案可以使用另一个控件(即 ListView 或 GridView 不折不扣地实现我想要的),我会很高兴。
我目前的解决方案是手动修改 ItemsSource 并将其分解,然后创建多个 pre-determined 大小的 DataGrid,这不是很灵活。
测试 DataGrid.ItemsPanel 和 WrapPanel
DataGrid 只显示数据行。因此,如果我们将 WrapPanel.Orientation 设置为“水平”:
<DataGrid x:Name="dg" ItemsSource="{Binding _humans}">
<DataGrid.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</DataGrid.ItemsPanel>
</DataGrid>
ListView 和 GridView
如果我们想单独显示 属性 列,我们应该为每个 属性 使用一个 ListView。 GridView 将用于显示 header。在 XAML 文档中,我们为 WrapPanel 设置了名称。
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<WrapPanel Name="wraper" Orientation="Horizontal">
</WrapPanel>
</ScrollViewer>
</Grid>
后面的代码实现为:
public partial class MainWindow : Window
{
private IList<Human> _humans;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CreateHumans();
wraper.Children.Add(CreateListViewFor("FirstName"));
wraper.Children.Add(CreateListViewFor("LastName"));
wraper.Children.Add(CreateListViewFor("Age"));
wraper.Children.Add(CreateListViewFor("Bday", "Birthday"));
wraper.Children.Add(CreateListViewFor("Salary"));
wraper.Children.Add(CreateListViewFor("Id", "Identification"));
}
private void CreateHumans()
{
_humans = new List<Human>();
for (int i = 10; i < 20; i++)
{
var human = new Human();
human.FirstName = "Zacharias";
human.LastName = "Barnham";
human.Bday = DateTime.Parse("1.3.1990");
human.Id = "ID-1234-zxc";
human.Salary = 2_000_000;
_humans.Add(human);
}
}
private ListView CreateListViewFor(string propertyName, string header)
{
var lv = new ListView();
var gv = new GridView();
lv.ItemsSource = _humans;
lv.View = gv;
lv.SelectionChanged += UpdateSelectionForAllListViews;
gv.Columns.Add(new GridViewColumn() { Header = header, DisplayMemberBinding = new Binding(propertyName), Width = 100 });
return lv;
}
private ListView CreateListViewFor(string propertyName)
{
return CreateListViewFor(propertyName, propertyName);
}
private void UpdateSelectionForAllListViews(object sender, SelectionChangedEventArgs e)
{
int index = (sender as ListView).SelectedIndex;
foreach (var child in wraper.Children)
{
(child as ListView).SelectedIndex = index;
}
}
}
我们调用 CreateListViewFor() 方法为 WrapPanel 提供 ListView objects。我们为 Selection Changed 事件创建回调以更新每个列表的选择。样式由您决定。
我正在尝试实现一个可以 'wrap' WPF DataGrid 的解决方案 - 我的意思是整个列和行都换行,不是 他们的文字或内容(见下图)。
我有一组由列和行组成的数据(列 headers),我想在限制 window 的宽度限制时换行,而不是使用水平滚动表示数据显示的栏 off-screen.
我看过使用 WrapPanel 作为我的 DataGrid 的 ItemsPanelTemplate,但是我无法在此基础上进一步实现我想要的。
<DataGrid.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</DataGrid.ItemsPanel>
如果有一个答案可以使用另一个控件(即 ListView 或 GridView 不折不扣地实现我想要的),我会很高兴。
我目前的解决方案是手动修改 ItemsSource 并将其分解,然后创建多个 pre-determined 大小的 DataGrid,这不是很灵活。
测试 DataGrid.ItemsPanel 和 WrapPanel
DataGrid 只显示数据行。因此,如果我们将 WrapPanel.Orientation 设置为“水平”:
<DataGrid x:Name="dg" ItemsSource="{Binding _humans}">
<DataGrid.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</DataGrid.ItemsPanel>
</DataGrid>
ListView 和 GridView
如果我们想单独显示 属性 列,我们应该为每个 属性 使用一个 ListView。 GridView 将用于显示 header。在 XAML 文档中,我们为 WrapPanel 设置了名称。
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<WrapPanel Name="wraper" Orientation="Horizontal">
</WrapPanel>
</ScrollViewer>
</Grid>
后面的代码实现为:
public partial class MainWindow : Window
{
private IList<Human> _humans;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CreateHumans();
wraper.Children.Add(CreateListViewFor("FirstName"));
wraper.Children.Add(CreateListViewFor("LastName"));
wraper.Children.Add(CreateListViewFor("Age"));
wraper.Children.Add(CreateListViewFor("Bday", "Birthday"));
wraper.Children.Add(CreateListViewFor("Salary"));
wraper.Children.Add(CreateListViewFor("Id", "Identification"));
}
private void CreateHumans()
{
_humans = new List<Human>();
for (int i = 10; i < 20; i++)
{
var human = new Human();
human.FirstName = "Zacharias";
human.LastName = "Barnham";
human.Bday = DateTime.Parse("1.3.1990");
human.Id = "ID-1234-zxc";
human.Salary = 2_000_000;
_humans.Add(human);
}
}
private ListView CreateListViewFor(string propertyName, string header)
{
var lv = new ListView();
var gv = new GridView();
lv.ItemsSource = _humans;
lv.View = gv;
lv.SelectionChanged += UpdateSelectionForAllListViews;
gv.Columns.Add(new GridViewColumn() { Header = header, DisplayMemberBinding = new Binding(propertyName), Width = 100 });
return lv;
}
private ListView CreateListViewFor(string propertyName)
{
return CreateListViewFor(propertyName, propertyName);
}
private void UpdateSelectionForAllListViews(object sender, SelectionChangedEventArgs e)
{
int index = (sender as ListView).SelectedIndex;
foreach (var child in wraper.Children)
{
(child as ListView).SelectedIndex = index;
}
}
}
我们调用 CreateListViewFor() 方法为 WrapPanel 提供 ListView objects。我们为 Selection Changed 事件创建回调以更新每个列表的选择。样式由您决定。