2012-03-01 69 views
4

我试图以编程方式选择在WPF DataGrid中的整列。我的代码似乎工作,但它真的很慢!我猜这是因为它不断需要调用ScrollIntoView。有人可以通过解决方案帮助我加速或选择整个色谱柱吗?DataGrid中选择列

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

我尝试通过@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中选择一个单元格/行,它不会调用代码中的属性设置器。正如你所看到的绑定是TwoWay,所以我不知道这个问题。

另一个更新:问题肯定似乎是虚拟化。如果我关闭虚拟化(VirtualizingStackPanel.IsVirtualizing =“False”),它工作正常。

回答

2

一个更有效的方法很可能是已经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> 

最后,实现你的选择,所有的代码如下所示(这并不全选年龄,你可能想使一个更通用/优雅的实现;)):

 foreach (MyData user in Users) 
     { 
      user.AgeSelected = true; 
     } 

你”将不得不照顾,以确保您所有NotifyPropertyChanged行为一字排开,因为你期待网格认识到其绑定的内部集合属性被更新。

+0

我不知道如何结合是可行的。例? – KrisTrip 2012-03-01 19:31:23

+0

你稍微误解的问题,将默认选择单位是行,如果希望选择一列人会需要一个IsSelected属性为每一个属性,不同的细胞风格结合到它的每一列。 – 2012-03-01 19:44:31

+0

这就是我要提出,H.B.,虽然我检讨我写的,我的语言是有点模糊。将以示例进行修改。 – ianschol 2012-03-01 19:54:59