WPF: refreshing value of a computed field in an item of an ObservableCollection

佐手、 提交于 2019-12-25 06:47:29

问题


I have an issue with my WPF ObservableCollection.

I have an ObservableCollection (_additionalCosts) bound to a ListView which includes one readonly computed field based on the value of other properties in the item and, crucially, the value of another dropdown.

When I change the selected item of the dropdown I would like the computed field to refresh, which it is not doing at the moment.

My view class looks like this:

[Serializable]
public class BookingView : ViewBase
{
    private ObservableCollection<AdditionalCostView> _additionalCosts = new ObservableCollection<AdditionalCostView>();

    //..other members

    public ReferenceDataView SellPriceCurrency
    {
        get { return _sellPriceCurrency; }
        set
        {
            this.OnPropertyChanged("SellPriceCurrency");
        }
    }

    //..other members
}

The items of the AdditionalCostView looks like this:

[Serializable()]
public class AdditionalCostView : ViewBase, IEquatable<AdditionalCostView>
{
    //..other members
    private decimal? _margin;

    public decimal? Margin
    {
        get
        {
            if (_charterSellPriceCurrency == null)
                return null;

            if (_sellPrice.HasValue && _buyPrice.HasValue)
            {
                return _exchangeRateConverter.ConvertUsingExchangeRate(1, _sellPriceCurrency.Name, _charterSellPriceCurrency.Name, _sellPrice.Value) -
                       _exchangeRateConverter.ConvertUsingExchangeRate(1, _buyPriceCurrency.Name, _charterSellPriceCurrency.Name, _buyPrice.Value);
            }

            return null;
        }
    }

    //..other members
}

If you need any more code, please let me know.

How do I accomplish this?


回答1:


Here is a simple example of how you can use computed fields in WPF. Let's say we have a property Result whose value depends on another property Multiplier. This is how you would get this scenario to work... please note that you must implement the INotifyPropertyChanged interface to get this to work:

public string Result
{
    get { return Multiplier * someFixedValue; }
}

public string Multiplier
{
    get { return multiplier; }
    set { multiplier = value; NotifyPropertyChanged("Multiplier", "Result"); }
}

...

protected override void NotifyPropertyChanged(params string[] propertyNames)
{
    if (PropertyChanged != null)
    {
        foreach (string propertyName in propertyNames)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

In this way, each time the Multiplier property is updated, the Result property will also be updated in the UI.




回答2:


I suppose that your ViewBase class implements INotifyPropertyChanged. From your code I understand that everytime that _charterSellPriceCurrency or _sellPrice or _buyPrice changes, the Margin property has to be recalculated.

This code consider just the _charterSellPriceCurrency changings, but it is easy to extend it to the other fields.

private YourType _charterSellPriceCurrency;
private Nullable<decimal> _margin;

public YourType CharterSellPriceCurrency 
{
    get
    {
        return _charterSellPriceCurrency;
    }
    private set
    {
        if (value != _charterSellPriceCurrency)
        {
            _charterSellPriceCurrency = value;
            OnPropertyChanged("CharterSellPriceCurrency");
            CalculateMargin();
        }
    }
}

public Nullable<decimal> Margin
{
    get
    {
        return _margin;
    }
    private set
    {
        if (value != _margin)
        {
            _margin = value;
            OnPropertyChanged("Margin");
        }
    }
}

private void CalculateMargin()
{
    if (_charterSellPriceCurrency == null)
    {
        Margin = null;
        return;
    }

    if (_sellPrice.HasValue && _buyPrice.HasValue)
    {
        Margin = _exchangeRateConverter.ConvertUsingExchangeRate(1, _sellPriceCurrency.Name, _charterSellPriceCurrency.Name, _sellPrice.Value) -
                _exchangeRateConverter.ConvertUsingExchangeRate(1, _buyPriceCurrency.Name, _charterSellPriceCurrency.Name, _buyPrice.Value);
        return;
    }

    Margin = null;
}

The point is that you must notify to the UI that the Margin property changed, no matter if it is a read only property, if it changes you have to raise the event. Otherwise the UI can't be aware that it was recalculated.



来源:https://stackoverflow.com/questions/27945774/wpf-refreshing-value-of-a-computed-field-in-an-item-of-an-observablecollection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!