C # MVVM Расчет общего - PullRequest
1 голос
/ 09 июня 2010

Мне нужно рассчитать стоимость сделки на основе выбранной цены и количества.Как можно

Следующее - моя ViewModel:

class ViewModel : ViewModelBase
{
    public Trade Trade
    {
        get { return _trade; }
        set { SetField(ref _trade, value, () => Trade); }
    } private Trade _trade;

    public decimal TradeValue
    {
        get { return Trade.Amount * Trade.Price; }
    } 

}

ViewModelBase наследует INotifyPropertyChanged и содержит SetField ()

Следующее является классом Trade:

public class Trade : INotifyPropertyChaged
{
    public virtual Decimal Amount
    {
        get { return _amount; }
        set { SetField(ref _amount, value, () => Amount); }
    } private Decimal _amount;
    public virtual Decimal Price
    {
        get { return _price; }
        set { SetField(ref _price, value, () => Price); }
    } private Decimal _price;
    ......
}

Я знаю, что благодаря дизайну, мой TradeValue рассчитывается только один раз (при первом запросе), а пользовательский интерфейс не обновляется при изменении суммы / цены.Каков наилучший способ достижения этого?

Любая помощь с благодарностью.

Обновление: Реализация INotifyPropertyChanged:

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        var body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }
    protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(selectorExpression);
        return true;
    }

Оба ответа работают,теперь я не знаю, какой из них выбрать лучший ответ.Ответ Люка кажется лучше, так как, кажется, меньше повторений кода, хотя простое прослушивание события OnPropertyChanged кажется более легким.

Ответы [ 3 ]

2 голосов
/ 09 июня 2010

Вот как я обычно это делаю:

private bool has_inited_tradevalue_linkage = false;
public decimal TradeValue
{
    get 
    { 
        if(!has_inited_tradevalue_linkage)
        {
            has_inited_tradevalue_linkage = true;
            this.PropertyChanged += (_, e) => 
            {
                if(e.PropertyName.Equals("Amount") || e.PropertyName.Equals("Price"))
                    OnPropertyChanged("TradeValue");
            };
        }
        return Trade.Amount * Trade.Price; }
}

таким образом, связь строится лениво (поэтому вы не публикуете события, которые никому не интересны), и вся логика все еще содержится в этом свойстве. И наоборот, вы можете просто добавить вызовы к OnPropertyChanged("TradeValue") в установщиках Price и Amount, но это немного «испачкает» остальную часть класса (по крайней мере, на мой взгляд). Я очень успешно использовал этот шаблон для создания похожих «зависимых» свойств.

Другой вариант - просто отслеживать зависимости:

в ViewModelBase вы можете добавить это:

личный словарь> DependencyMap = новый словарь> (); protected void AddPropertyDependency (String prop, String зависимыйProp) { если (DependencyMap.ContainsKey (проп)) { DependencyMap [проп] .Add (dependantProp); } еще { DependencyMap [prop] = new List {depenndantProp}; } }

тогда в вашем OnPropertyChanged методе:

protected void OnPropertyChanged(String prop)
{
    var eh = PropertyChanged;
    if(eh != null)
    {
        eh(this, new PropertyChangedEventArgs(prop);
        if(DependencyMap.ContainsKey(prop))
        {
            foreach(var p in DependencyMap[prop])
                OnPropertyChanged(p);//recursive call would allow for arbitrary dependencies
        }
    }
}

тогда в конструкторе вашего класса вы просто определите зависимости своего свойства:

public ViewModel()
{
    AddPropertyDependency("Amount", "TradeValue");
    AddPropertyDependency("Price", "TradeValue");
}

это определенно более общее решение, и большинство изменений в вашем базовом классе.

1 голос
/ 09 января 2013
private void UpdateValue()
        {
            this.Value = this.Acres * this.YieldPerAcre * this.UnitPrice;
        }      
       public double Acres
        {
            get { return _cropProductionRecord.Acres; }
            set
            {
                _cropProductionRecord.Acres = value;
                OnPropertyChanged("Acres");
                UpdateValue();
            }
        }
        public double YieldPerAcre
        {
            get { return _cropProductionRecord.YieldPerAcre; }
            set
            {
                _cropProductionRecord.YieldPerAcre = value;
                OnPropertyChanged("YieldPerAcre");
                UpdateValue();
            }
        }

        public double UnitPrice
        {
            get { return _cropProductionRecord.UnitPrice; }
            set
            {
                _cropProductionRecord.UnitPrice = value;
                OnPropertyChanged("UnitPrice");
                UpdateValue();
            }
        }
        public double Value
        {
            get { return _cropProductionRecord.Value; }
            set
            {
                _cropProductionRecord.Value = value;
                OnPropertyChanged("Value");
            }
        }
1 голос
/ 09 июня 2010

Подпишитесь на событие PropertyChanged класса Trade в методе set для свойства Trade в вашем классе VM.В этом обработчике событий разместите свойство, измененное для свойства TradeValue.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...