修改CellEditEnding事件

时间:2015-12-14 13:05:44

标签: c# wpf datagrid datatable

我一直在尝试在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");

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

所以问题是我可以做些什么来实现新行中的UI更新,因为它可以在不使用提供的第二个代码片段的情况下处理现有行?我觉得我错过了什么......

编辑:使用ClipboardPaste也可用于设置新值,但由于某种原因原始编辑的值将丢失。

Edit2:xaml目前是普通的DataGrid,我试图手动完成列和它们的绑定但是因为我还没有让它们工作我已经删除它们以保持示例代码简单

<DataGrid x:Name="MyDataGrid" />

Edit3:添加此图片以更好地描述问题。因此,在单击下一个单元格后,我希望显示文本 Example image of the problem

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

Edit5:我希望这可以与DataTable一起使用,因为我需要它的其他功能

2 个答案:

答案 0 :(得分:2)

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

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";
    }
}

答案 1 :(得分:0)

我建议您使用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 Control)。

如果您遇到代码问题,我将非常乐意为您提供帮助。 此致

<强>更新  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>