问题
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