2012-03-01 68 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