修改CellEditEnding事件的DataGrid单元格值

本文关键字:单元格 DataGrid CellEditEnding 事件 修改 | 更新日期: 2023-09-27 18:26:39

我一直试图在WPF DataGrid控件的CellEditEnding事件处理程序中更改同一行中的不同单元格值。

如果编辑现有行中的单元格值,它将按预期工作。但是,添加新行时,如果鼠标单击另一个单元格值而不进入编辑模式,则更改不会反映到UI中。

按tab键将焦点移动到下一个单元格也可以正常工作,但它不应该也适用于单击吗?

public MainWindow()
{
    InitializeComponent();
    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(new DataColumn());
    dataTable.Columns.Add(new DataColumn());
    DataRow existingRow = dataTable.NewRow();
    dataTable.Rows.Add(existingRow);
    this.MyDataGrid.ItemsSource = dataTable.DefaultView;
    this.MyDataGrid.CellEditEnding += MyDataGrid_CellEditEnding;
}
void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    (e.Row.Item as DataRowView).Row[1] = "a string that should be displayed immediatly";
}

到目前为止,我已经尝试更改绑定UpdateSourceTrigger、NotifyOnSourceUpdated和NotifyOnTargetUpdated,但似乎什么都不起作用。我还试着通过阅读相关主题来进行相应的修复:http://codefluff.blogspot.fi/2010/05/commiting-bound-cell-changes.html

但这些似乎也无济于事。。

我发现的一种工作方式是以下片段:

var frameworkElement = this.MyDataGrid.Columns[1].GetCellContent(e.Row);
frameworkElement.SetValue(TextBlock.TextProperty, "a string that should be displayed immediatly");

但我不想依赖dependencyproperties,因为我可能不知道底层的显示类型。

因此,问题是,在不使用提供的第二个代码片段的情况下,如何在新行中实现UI更新?我觉得我错过了什么。。

编辑:使用剪贴板粘贴也可以设置新值,但由于某些原因,原始编辑值将丢失。

第2版:xaml目前是纯DataGrid,我曾尝试手动完成列及其绑定,但由于我没有让它们工作,我已经删除了它们,以保持示例代码的简单

<DataGrid x:Name="MyDataGrid" />

第3版:添加此图片以更好地描述问题。因此,在单击下一个单元格后,我希望显示文本问题的示例图像

Edit4:使用snoop查看单元格似乎将元素设置为可见,同时调用.UpdateTarget();因为绑定似乎有帮助,但它不是自动工作的。还在想是什么原因。。

第5版:我希望这能与DataTable一起使用,因为我需要它的其他功能

修改CellEditEnding事件的DataGrid单元格值

在测试了大量不同类型的解决方案后,我在开始编辑单元格时添加了行。由于我所寻求的功能是在现有行中工作,所以它确实解决了问题。

public class MyDataGrid : DataGrid
{
    protected override void OnBeginningEdit(DataGridBeginningEditEventArgs e)
    {
        base.OnBeginningEdit(e);
        this.CommitEdit();
    }
    protected override void OnCellEditEnding(DataGridCellEditEndingEventArgs e)
    {
        base.OnCellEditEnding(e);
        (e.Row.Item as DataRowView).Row[1] = "a string that should be displayed immediatly";
    }
}

我建议您使用MVVM的方式,然后您将通过WPF本身的内置通知机制来满足您的要求,在数据上下文中某个属性的upfdate上,您可以触发另一个属性的更新。示例:1.Xaml编码:

<Window x:Class="DataGridSoHelpAttempt.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dataGridSoHelpAttempt="clr-namespace:DataGridSoHelpAttempt"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <dataGridSoHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid>
    <DataGrid x:Name="MyDataGrid" ItemsSource="{Binding DataSource}"/>
</Grid></Window>

2.查看型号代码:

public class MainViewModel:BaseObservableObject
{
    public MainViewModel()
    {
        DataSource = new ObservableCollection<BaseData>(new List<BaseData>
        {
            new BaseData {Name = "John"},
            new BaseData {Name = "Ron"},
            new BaseData {Name = "Bob"},
        });
    }
    public ObservableCollection<BaseData> DataSource { get; set; }
}

3.型号代码:

public class BaseData:BaseObservableObject
{
    private string _name;
    private string _description;
    public virtual string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
            Description = "a string that should be displayed immediatly";
        }
    }
    public virtual object Description
    {
        get { return _description; }
        set
        {
            _description = (string) value;
            OnPropertyChanged();
        }
    }
}

4.BaseObservableObject一个基本的INotifyPropertyChanged实现:

public class BaseObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
    {
        var propName = ((MemberExpression)raiser.Body).Member.Name;
        OnPropertyChanged(propName);
    }
    protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(name);
            return true;
        }
        return false;
    }
}

5.请记住,您的模型的属性对象可能很复杂(如描述另一个视图模型的图像或类),但在这种情况下,您必须对数据网格列或/和单元格进行模板化(示例链接:WPF DataGrid控件)。

如果您在代码方面遇到问题,我将非常乐意为您提供帮助。问候

更新1.代码隐藏-您应该更新DataTable,但请考虑到必须对表中已经存在的行执行更新:

public partial class MainWindow : Window
{
    private readonly DataTable _dataTable;
    public MainWindow()
    {
        InitializeComponent();
        this.MyDataGrid.CellEditEnding += MyDataGrid_CellEditEnding;
        _dataTable = new DataTable();
        _dataTable.Columns.Add(new DataColumn());
        _dataTable.Columns.Add(new DataColumn());
        DataRow existingRow = _dataTable.NewRow();
        _dataTable.Rows.Add(existingRow);
        this.MyDataGrid.ItemsSource = _dataTable.DefaultView;
    }

    void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        var dataRowView = (e.Row.Item as DataRowView);
        var columnIndex = e.Column.DisplayIndex;
        var rowIndex = e.Row.GetIndex();
        var dv = _dataTable.DefaultView;
        var nextColumnIndex = columnIndex + 1;
        if (dv.Table.Columns.Count <= nextColumnIndex || dv.Table.Rows.Count <= rowIndex) return;
        dv.Table.Rows[rowIndex][nextColumnIndex] = "a string that should be displayed immediatly";
    }
}

2.Xaml:

<Window x:Class="GridViewWitaFDataTableSoHelpAttempt.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid x:Name="MyDataGrid" />
</Grid></Window>