Home > Mobile >  How force WPF-DataGrid to commit changes to the SourceItem directly after cell change?
How force WPF-DataGrid to commit changes to the SourceItem directly after cell change?

Time:05-26

The XAML of my dataGrid looks like this:

<DataGrid x:Name="orders"/>

It is initialized via this function:

private void InitOrders()
{
    orders.ItemsSource = null;
    var selection = (from ord in m_DbSession.Query<Order>() select new OrderDatasource(ord, m_DbSession));
    if (selection != null)
    {
        orders.ItemsSource = selection.ToList();
    }
}

OrderDatasource is a class which implements IEditableObject connects to the database

class OrderDatasource : IEditableObject
{
    public OrderDatasource(Order initialObject, ISessionWrapper dbSession)
    {
        m_DbObject = initialObject;
        m_dbSession= dbSession
    }
    

    Order m_DbObject;
    ISessionWrapper m_dbSession;
    public int Count
    {
        get
        {
            return m_DbObject.Count;
        }
        set
        {
            m_DbObject.Count = value;
        }
    }

    public decimal LimitedPricePerShare
    {
        get
        {
            return m_DbObject.LimitedPricePerShare;
        }
        set
        {
            m_DbObject.LimitedPricePerShare = value;
        }
    }

    public decimal TotalPrice
    {
        get
        {
            return Count * LimitedPricePerShare;
        }
    }       
    
    public void BeginEdit()
    {

    }

    public void CancelEdit()
    {

    }

    public void EndEdit()
    {
        if (m_DBSession != null)
        {
            Debug.WriteLine("Datasource.EndEdit");
            using (var tx = m_DBSession.BeginTransaction())
            {
                m_DBSession.SaveOrUpdate(GetDbObject());
                tx.Commit();
            }
        }
        else
        {
            throw new NoDatabaseSessionProvidedException();
        }
    }       
}

So now I want to be able to refresh the value of TotalPrice in the DataGrid after the content of the cell "Count" was changed but !before! the user changed the selected row.

Unfortunately the setter of OrderDatasource.Count is only called after the user clicks into another row, !not! if the user clicks into the cell "LimitedPricePerShare" in the same row. So the calculated value of "TotalPrice" is wrong.

So: Is there a way to force the DateGrid to call the setters after a cell has changed?

Things I tried which have not worked:

  • Calling CommitEdit in the event CellEditEnding

    private void Orders_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { (sender as DataGrid).CommitEdit(); }

CodePudding user response:

Ok, It seems like I have found a way to do this. Its quite complicated but anyway:

First I used the event AutoGeneratingColumn where I change the UpdateSourceTrigger of the binding to UpdateSourceTrigger.LostFocus

private void orders_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.Column.Header.ToString() == "Count")
    {
        var textColumn = new DataGridTextColumn();
        textColumn.Binding = new Binding(e.PropertyName) 
        { 
            UpdateSourceTrigger = UpdateSourceTrigger.LostFocus 
        };

        e.Column = textColumn;
    }
}

Then I implemented INotifyPropertyChanged in OrderDatasource and added the following code:

class OrderDatasource : IEditableObject
{
    //Same code as in the question
    //...
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

   public int Count
    {
        get
        {
            return m_DbObject.Count;
        }
        set
        {
            m_DbObject.Count = value;
            OnPropertyChanged(nameof(Count));
            OnPropertyChanged(nameof(TotalPrice));
        }
    }

    public decimal LimitedPricePerShare
    {
        get
        {
            return m_DbObject.LimitedPricePerShare;
        }
        set
        {
            m_DbObject.LimitedPricePerShare = value;
            OnPropertyChanged(nameof(LimitedPricePerShare));
            OnPropertyChanged(nameof(TotalPrice));
        }
    }
}

Now the Value of "TotalPrice" changes instantly after changing column but without changing the row.

CodePudding user response:

Or just do directly in your xaml if you are not building dynamically with code. Ex:

<TextBox Text="{Binding WhateverProperty, UpdateSourceTrigger=LostFocus}" />
  • Related