WPF DataGrid 列更改事件。如何检测列大小调整?
WPF DataGrid Column Changed Event. How to Detect Column Resizing?
我对调整列大小的默认行为有疑问:
如果 DataGrid 对其容器而言太宽,则会出现水平滚动条。
如果我将栏向右拖动并调整最右侧列的大小,滚动条会保持在右侧。
就我而言,我不希望出现这种行为。
滚动条要么不粘在右边,
或者,完美的是,像 MS Excel.
这样的调整大小预览
有人能告诉我如何实现吗?
编辑1:
这种行为很好(不粘在右边):
我不喜欢的是:
如果我能很容易地意识到这一点,我宁愿:
/编辑1
我正在为一个简单的 WPF 应用程序使用 .Net 4.8。
如果需要示例,下面将显示两个网格,左侧的网格可用于该行为:
<Window x:Class="DataGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataGridTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MasterViewModel/>
</Window.DataContext>
<DockPanel>
<Button DockPanel.Dock="Bottom" Command="{Binding DisplaySelectionCountCommand}">Display Selection Count</Button>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0" ItemsSource="{Binding Items}" AutoGenerateColumns="False"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True" HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="1" ItemsSource="{Binding Items}"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True"/>
</Grid>
</DockPanel>
</Window>
当我建议收听 SizeChanged
事件时,我并不是说 DataGrid
是来源。
既然对栏目感兴趣,那当然要监听cell事件了:
MainWindow.xaml
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private void DataGridCell_SizeChanged(object sender, SizeChangedEventArgs e)
=> (sender as DataGridCell).BringIntoView();
这是一个替代版本,展示了如何使用 DataGrid
的 ScrollViewer
来更好地控制滚动位置:
MainWindow.xaml
<DataGrid x:Name="DataGrid"
ScrollViewer.ScrollChanged="DataGrid_ScrollChanged">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private double OriginalScrollPosition { get; set; }
private bool IsResizingColumn { get; set; }
private void DataGrid_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (this.IsResizingColumn
&& TryFindVisualChildElement(dataGrid, out ScrollViewer scrollViewer))
{
this.Dispatcher.InvokeAsync(() =>
{
scrollViewer.ScrollToHorizontalOffset(this.OriginalScrollPosition);
this.IsResizingColumn = false;
}, DispatcherPriority.Background);
}
}
private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
var dataGridCell = sender as DataGridCell;
if (TryFindVisualChildElement(this.DataGrid, out ScrollViewer scrollViewer))
{
this.OriginalScrollPosition = scrollViewer.HorizontalOffset;
this.IsResizingColumn = true;
}
}
private bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild resultElement)
where TChild : DependencyObject
{
resultElement = null;
if (parent is Popup popup)
{
parent = popup.Child;
if (parent == null)
{
return false;
}
}
for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex++)
{
DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
if (childElement is TChild child)
{
resultElement = child;
return true;
}
if (TryFindVisualChildElement(childElement, out resultElement))
{
return true;
}
}
return false;
}
我对调整列大小的默认行为有疑问:
如果 DataGrid 对其容器而言太宽,则会出现水平滚动条。 如果我将栏向右拖动并调整最右侧列的大小,滚动条会保持在右侧。
就我而言,我不希望出现这种行为。 滚动条要么不粘在右边, 或者,完美的是,像 MS Excel.
这样的调整大小预览有人能告诉我如何实现吗?
编辑1:
这种行为很好(不粘在右边):
我不喜欢的是:
如果我能很容易地意识到这一点,我宁愿:
/编辑1
我正在为一个简单的 WPF 应用程序使用 .Net 4.8。
如果需要示例,下面将显示两个网格,左侧的网格可用于该行为:
<Window x:Class="DataGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataGridTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MasterViewModel/>
</Window.DataContext>
<DockPanel>
<Button DockPanel.Dock="Bottom" Command="{Binding DisplaySelectionCountCommand}">Display Selection Count</Button>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0" ItemsSource="{Binding Items}" AutoGenerateColumns="False"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True" HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="1" ItemsSource="{Binding Items}"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True"/>
</Grid>
</DockPanel>
</Window>
当我建议收听 SizeChanged
事件时,我并不是说 DataGrid
是来源。
既然对栏目感兴趣,那当然要监听cell事件了:
MainWindow.xaml
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private void DataGridCell_SizeChanged(object sender, SizeChangedEventArgs e)
=> (sender as DataGridCell).BringIntoView();
这是一个替代版本,展示了如何使用 DataGrid
的 ScrollViewer
来更好地控制滚动位置:
MainWindow.xaml
<DataGrid x:Name="DataGrid"
ScrollViewer.ScrollChanged="DataGrid_ScrollChanged">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private double OriginalScrollPosition { get; set; }
private bool IsResizingColumn { get; set; }
private void DataGrid_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (this.IsResizingColumn
&& TryFindVisualChildElement(dataGrid, out ScrollViewer scrollViewer))
{
this.Dispatcher.InvokeAsync(() =>
{
scrollViewer.ScrollToHorizontalOffset(this.OriginalScrollPosition);
this.IsResizingColumn = false;
}, DispatcherPriority.Background);
}
}
private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
var dataGridCell = sender as DataGridCell;
if (TryFindVisualChildElement(this.DataGrid, out ScrollViewer scrollViewer))
{
this.OriginalScrollPosition = scrollViewer.HorizontalOffset;
this.IsResizingColumn = true;
}
}
private bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild resultElement)
where TChild : DependencyObject
{
resultElement = null;
if (parent is Popup popup)
{
parent = popup.Child;
if (parent == null)
{
return false;
}
}
for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex++)
{
DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
if (childElement is TChild child)
{
resultElement = child;
return true;
}
if (TryFindVisualChildElement(childElement, out resultElement))
{
return true;
}
}
return false;
}