【问题标题】:How do I set the value of the selected WPF DataGrid cell to the value of the cell above?如何将所选 WPF DataGrid 单元格的值设置为上面单元格的值?
【发布时间】:2019-12-23 18:12:54
【问题描述】:

上下文

我在 WPF MVVM 应用程序中有一个 DataGrid,其中包含来自绑定集合的多行。集合中的每个对象都具有不同类型的属性,例如Name 是一个字符串,InsertDate 是一个 DateTime 等等。

由于各种原因,DataGrid SelectionUnit 需要设置为“Cell”。

问题

我正在设置一个链接到一个命令的键绑定,该命令会将当前选定的单元格设置为上一行中相同单元格的值。 (我已经处理了没有前一行的情况)。

我的尝试

我成功地将整个 DataGrid 作为 CommandParameter 传递给命令:

<KeyBinding Command="{Binding RepeatFieldAboveCommand}"
            CommandParameter="{Binding ., ElementName=identitiesGrid}"
            Key="F5"  />

...然后在命令中...

public override void Execute(object parameter)
{
    var dataGrid = parameter as DataGrid;
}

然后我可以访问绑定到当前行和前一行的对象

Identity currentRow = dataGrid.CurrentItem as Identity;       

int currentRowIndex = dataGrid.Items.IndexOf(dataGrid.CurrentItem);
Identity previousRow = dataGrid.Items[currentRowIndex - 1] as Identity;

我也可以用

获取选中列的索引
int displayIndex = dataGrid.CurrentColumn.DisplayIndex;

但我找不到直接引用单元格值以进行复制的方法。我考虑过通过 CommandParameter 传递一些更有用的东西,但我想不出是什么。

【问题讨论】:

    标签: c# wpf mvvm datagrid copy


    【解决方案1】:

    “单元格值”不仅仅是原始值。它们是由与每种类型的列关联的模板创建的视觉内容 - 例如DataGridTextColumn 默认包含 TextBlock

    您可以使用DataGridColumn.GetCellContent() 获取列的内容。例如,DataGridTextColumn:

    TextBlock tb = dataGrid.Columns[x].GetCellContent(dataGrid.Items[y]) as TextBlock;
    string theCellValue = tb.Text;
    

    以上仅适用于DataGridTextColumn,如果您有不同类型的列,显然不可靠,尽管在这种情况下您可以检测当前列的类型并使用适当的逻辑来获取其“值”。

    另一种方法是获取绑定的属性名称并通过您的 DataContext 对象复制值:

    var currentItem = dataGrid.CurrentItem;
    int currentRowIndex = dataGrid.Items.IndexOf(currentItem);
    if (currentRowIndex <= 0) return;
    var previousItem = dataGrid.Items[currentRowIndex - 1] as YourDataObject;
    DataGridBoundColumn boundColumn = dataGrid.CurrentColumn as DataGridBoundColumn;
    if (boundColumn != null)
    {
        var binding = boundColumn.Binding as Binding;
        if (binding != null)
        {
            var propertyPath = binding.Path.Path;
            var property = typeof(YourDataObject).GetProperty(propertyPath);
            var value = property.GetValue(previousItem);
            property.SetValue(currentItem, value);
        }
    }
    

    但是,这不适用于 DatGridTemplateColumn 列,因为它们没有 Binding。在这种情况下,一个备用方案是使用模板列的SortMemberName,因为您通常将此设置为适当的属性以使模板列可排序。

    var currentItem = dataGrid.CurrentItem;
    int currentRowIndex = dataGrid.Items.IndexOf(currentItem);
    if (currentRowIndex <= 0) return;
    var previousItem = dataGrid.Items[currentRowIndex - 1] as YourDataObject;
    string propertyName = null;
    DataGridBoundColumn boundColumn = dataGrid.CurrentColumn as DataGridBoundColumn;
    if (boundColumn != null)
    {
        var binding = boundColumn.Binding as Binding;
        if (binding != null)
        {
            propertyName = binding.Path.Path;
        }
    }
    else if (dataGrid.CurrentColumn is DataGridTemplateColumn)
    {
        propertyName = dataGrid.CurrentColumn.SortMemberPath;
    }
    if (propertyName != null)
    {
        var property = typeof(YourDataObject).GetProperty(propertyName);
        var value = property.GetValue(previousItem);
        property.SetValue(currentItem, value);
    }
    

    可能还有其他考虑因素,例如单元格值的有效性、编辑模式、只读单元格和更复杂的绑定,具体到您的情况,也需要处理。

    【讨论】:

    • 完整、简洁并能胜任工作。示范回答!非常感谢您抽出宝贵的时间,如果您庆祝它,祝您圣诞快乐。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多