I am trying to programmatically select an entire column in a DataGrid WPF. My code seems to work, but it is REALLY slow! I guess this is because I constantly have to call ScrollIntoView. Can someone help me with a solution to speed it up or an alternative to select the entire column?
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; }
UPDATE
I am trying to find the solution suggested by @ianschol. Here is what I have (I bind the code in b / c. I don't know how many columns I need before executing):
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 }, } }, } }); }
and my IsSelected property:
private bool isSelected = false; public bool IsSelected { get { return this.isSelected; } set { this.isSelected = value; OnPropertyChanged("IsSelected"); } }
And the new SelectColumn code:
public static void SelectColumn(DataGrid grid, int column) { for (int i = 0; i < grid.Items.Count; i++) {
The problem is that if I update the IsSelected property in the code, it updates the GUI (kinda, its quirky), but not vice versa. That is, if I select a cell / row in the GUI, it does not call the customization tool in the code. As you can see, binding is TwoWay, so I'm not sure about this problem.
Other UPDATE: The problem is certainly related to virtualization. If I turn off virtualization (VirtualizingStackPanel.IsVirtualizing = "False"), it works fine.