简体   繁体   English

WPF-如何控制可观察的集合更新

[英]Wpf - How to control observable collection updates

In the parent there is a Observable Collection PendingPayment that has a list of all pending payments of sales with a column amount paid. 在父级中,有一个Observable Collection PendingPayment,其中列出了所有待处理的销售付款以及已支付的列金额。

Then the user can select a particular sale and open it in new child window. 然后,用户可以选择特定的销售并在新的子窗口中打开它。

The thing thats going wrong is if the user just edits the text box paid amount in child window and closes the window without saving the new paid amount to database,the observable collection containing Amount paid column in the parent window gets updated. 出问题的是,如果用户仅在子窗口中编辑文本框支付金额并关闭该窗口而不将新的支付金额保存到数据库中,则父窗口中包含“支付金额”列的可观察集合将被更新。

What I want is it the collection to get updated only when the values are updated in the database. 我想要的是仅当数据库中的值更新时才更新的集合。

This can be achieved by creating a copy of your sale object when the user select it in the list, and then using this copy as the view model of your child view. 这可以通过在用户在列表中选择销售对象时创建销售对象的副本,然后将该副本用作子视图的视图模型来实现。

You will then be able to set the new values in the original object from your list only once the save button has been clicked and the database update succeed. 只有在单击保存按钮并且数据库更新成功后,您才可以在列表中的原始对象中设置新值。

An other way to proceed if you need to edit only few of the object properties would be to create and editor object and use it as the child window's view model. 如果只需要编辑少量对象属性,另一种进行方法是创建和编辑对象,并将其用作子窗口的视图模型。 Something like this : 像这样的东西:

public class Sale
{
    public int PaidAmount { get; set; }
    public int Some { get; set; }
    public int More { get; set; }
    public int Properties { get; set; }
}

public class SaleEditor
{
    private Sale _sale;

    public int PaidAmount { get; set; }

    public SaleEditor(Sale sale)
    {
        _sale = sale;
        PaidAmount = sale.PaidAmount;
    }

    public void Save()
    {
        // update your data here
        _sale.PaidAmount = PaidAmount;
    }
}

If you need your original object to update the database, then the save method could first update the object and the revert the changes if DB update failed : 如果您需要原始对象来更新数据库,则save方法可以首先更新对象,并在数据库更新失败时恢复更改:

    public void Save()
    {
        var oldAmount = _sale.PaidAmount;
        _sale.PaidAmount = PaidAmount;

        if (!SalesDB.Update(_sale))
            _sale.PaidAmount = oldAmount;
            // you could also read back the value from DB
    }

Whenever possible (I've never see a reason why it cannot),for listing purpose use proxy or flatted objects, you can implement this using projections query. 只要有可能(我从未见过无法这样做的原因),出于列出目的,请使用代理对象或扁平化对象,可以使用投射查询来实现此目的。 Then user select an item from a list and the only thing you need to grab is a key to load the full object with its required object graph as the use case might dictate. 然后,用户从列表中选择一个项目,您唯一需要抓住的是一个密钥,以根据用例的要求将完整的对象及其所需的对象图装入。

Here is a sample implementation using Entity Framework and c# lambda expressions: 这是使用Entity Framework和c#lambda表达式的示例实现:

Using anonymous object: 使用匿名对象:

var anonymousListProjection = DbContext.PendingPayments.Select( pp=> 
    new { pp.Order, pp.Amount})         


Using a hardcoded proxy: 使用硬编码的代理:

var hardcodedListProjection = DbContext.PendingPayments.Select( pp=> 
    new PendingPaymentProxy { Order = pp.Order, Amount = pp.Amount}) 

//To return an observable:    
var observableColl = new ObservableCollection<PendingPaymentProxy>
    (hardcodedListProjection.Tolist());

public class PendingPaymentProxy 
{
   public string Order { get; set; }
   public decimal Amount{ get; set; }    
}

Apart from avoiding possibles performance problems due to unintentional loading real objects, this way you only have to worry for your list when the user do save in the detail view. 除了避免由于意外加载真实对象而可能导致的性能问题之外,通过这种方式,您只需要在用户确实保存在详细视图中时担心列表即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM