DataGrid Select Column
本文关键字:Column Select DataGrid | 更新日期: 2023-09-27 18:26:12
我正在尝试用程序选择WPF数据网格中的整列。我的代码似乎可以工作,但它真的很慢!我猜这是因为它不断地调用ScrollIntoView。有人能帮我提供一个加快速度的解决方案,或者选择整个专栏的替代方案吗?
public static void SelectColumn(DataGrid grid, int column)
{
for (int i = 0; i < grid.Items.Count; i++)
{
// Select each cell in this column
var cell = DataGridHelper.GetCell(grid, i, column);
if (cell != null)
{
cell.IsSelected = true;
}
}
DataGridHelper.GetCell(grid, 0, column).Focus();
}
public static DataGridCell GetCell(DataGrid grid, int row, int column)
{
DataGridRow rowContainer = GetRow(grid, row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = TreeHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(rowContainer, grid.Columns[column]);
presenter = TreeHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
}
if (presenter != null)
{
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(rowContainer, grid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
}
return null;
}
public static DataGridRow GetRow(DataGrid grid, int index)
{
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
更新:
我正在试用ianschol提出的解决方案。以下是我所拥有的(我绑定在b/c后面的代码中,直到运行时我才知道我需要多少列):
for (int i = 0; i < this.CurrentData.Data[0].Length; i++)
{
TheGrid.Columns.Add(
new DataGridTextColumn
{
Header = (this.CurrentData.Rank > 1) ? string.Format(this.culture, headerFormatString, i + 1) : string.Empty,
Binding = new Binding(string.Format("[{0}].DataValue", i)) { ValidatesOnDataErrors = true, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged },
Width = DataGridLength.Auto,
ElementStyle = new Style
{
TargetType = typeof(TextBlock),
Triggers = { this.errorTrigger }
},
EditingElementStyle = new Style
{
TargetType = typeof(TextBox),
Triggers = { this.errorTrigger }
},
CellStyle = new Style
{
TargetType = typeof(DataGridCell),
Setters =
{
new Setter
{
Property = DataGridCell.IsSelectedProperty,
Value = new Binding(string.Format("[{0}].IsSelected", i)) { Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged },
}
},
}
});
}
和我的IsSelected属性:
private bool isSelected = false;
public bool IsSelected
{
get
{
return this.isSelected;
}
set
{
this.isSelected = value;
OnPropertyChanged("IsSelected");
}
}
新的SelectColumn代码:
public static void SelectColumn(DataGrid grid, int column)
{
for (int i = 0; i < grid.Items.Count; i++)
{
// Select each cell in this column
((DataItem[])(grid.Items[i]))[column].IsSelected = true;
}
}
问题是,如果我在代码中更新IsSelected属性,它会更新GUI(有点奇怪),但不会反过来。也就是说,如果我在GUI中选择了一个单元格/行,它就不会调用代码中的属性setter。正如你所看到的,绑定是双向的,所以我不确定这个问题。
另一个更新:问题显然与虚拟化有关。如果我关闭虚拟化(VirtualizingStackPanel.IsVirtualization="False"),它可以正常工作。
更有效的方法可能是在DataSource的类上具有IsSelected属性,这样每列都有相应的"IsSelected"属性。
public class MyData : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
Notify("Name");
}
}
private bool nameSelected = false;
public bool NameSelected
{
get { return nameSelected; }
set
{
nameSelected = value;
Notify("NameSelected");
}
}
//... etc ...
}
接下来,您可以更改每个列的CellStyle,以将单元格的IsSelected属性绑定到类上的相关IsSelected特性。
<DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False" HorizontalAlignment="Left" Name="scratchGrid" CanUserAddRows="False"
VerticalScrollBarVisibility="Auto" SelectionUnit="Cell">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="User Name" Width="200">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding NameSelected}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Age}" Header="User Age" Width="80">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding AgeSelected}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
最后,像这样实现select all代码(这确实在Age上进行了select all,你可能想做一个更通用/更优雅的实现;):
foreach (MyData user in Users)
{
user.AgeSelected = true;
}
您必须注意确保所有NotifyPropertyChanged行为都是对齐的,因为您希望网格识别出其绑定集合中的属性正在更新。