DataGrid选择列

时间:2012-03-01 19:16:00

标签: c# wpf datagrid

我正在尝试以编程方式选择WPF DataGrid中的整个列。我的代码似乎工作,但它真的很慢!我猜这是因为它不断调用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中选择一个单元格/行,它不会在代码中调用属性设置器。你可以看到绑定是TwoWay所以我不确定这个问题。

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

1 个答案:

答案 0 :(得分:2)

更有效的方法可能是在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 ...
}

接下来,您可以更改每个Column的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行为都排成一行,因为您希望网格能够识别其绑定集合中的属性正在更新。