最有效的通知视图方式(WPF / C#)

时间:2017-01-23 15:25:28

标签: c# wpf

我有一个汽车课。

class Car
{
  string ModelNum;
}

然后我有Car实例

class CarInstance
{
  string RegistrationNum;
}

我的viewmodel中有几个Cars实例。

 ViewModel(Car car)
 {
    CarInstance Ins = car.GetInstance();
 }

问题:假设汽车本身正在发生变化,需要通知视图模型该变更。什么是最有效的方法。我知道我可以使用事件(包括PRISM中的eventaggregator)。我想知道是否有更快的方法来做到这一点。

可以调用多个订阅者的Action参数?有这样的想法吗?

所有伪代码。

3 个答案:

答案 0 :(得分:1)

  

INotifyPropertyChanged比事件更具表现力吗?

INotifyPropertyChanged接口定义了PropertyChanged事件,即它实际上使用事件来通知视图。

  

假设汽车本身正在改变,它需要通知视图模型该更改。什么是最有效的方法。我知道我可以使用事件(包括PRISM中的eventaggregator)。我想知道是否有更快的方法来做到这一点。

在大多数情况下,举办活动的表现非常轻微,所以你不必担心:

How much performance overhead is there in using events?

使用事件聚合器的好处是,与直接引用每个发布者类的每个订阅者相比,您的类变得更加松散耦合:https://blog.magnusmontin.net/2014/02/28/using-the-event-aggregator-pattern-to-communicate-between-view-models/

但是,使用强引用或事件聚合器来提升事件是一种通知外部世界变化的好的,推荐的和快速的方法。

答案 1 :(得分:0)

如果属性更改为通知绑定到您的视图,那么将属性更改为通知是绝对正常的。它是MVVM中任何内容的首选方法。这就是你如何做到的

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

public class Car: INotifyPropertyChanged
{
    #region Property Changed
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion

    private string _modelNum;

    public string ModelNum 
    {
        get{ return _modelNum; }
        set 
        { 
            _modelNum = value; 
            //this will raise the notification
            OnPropertyChanged("ModelNum"); 
        }
    }
}

如果此汽车对象绑定到您的视图,您可以

Text="{Binding Car.ModelNum, UpdateSourceTrigger=PropertyChanged}"

UpdateSourceTrigger = PropertyChanged将在每次更新ModelName时更新UI,或者每当您从UI更新时都会更新ModelName。

答案 2 :(得分:0)

为notiyfing创建以下类:

public abstract class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();

    protected T Get<T>([CallerMemberName] string name = null)
    {
        Debug.Assert(name != null, "name != null");
        object value = null;
        if (_properties.TryGetValue(name, out value))
            return value == null ? default(T) : (T)value;
        return default(T);
    }
    protected void Set<T>(T value, [CallerMemberName] string name = null)
    {
        Debug.Assert(name != null, "name != null");
        if (Equals(value, Get<T>(name)))
            return;
        _properties[name] = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
    public void Notify<T>(Expression<Func<T>> memberExpression)
    {
        if (memberExpression == null)
        {
            throw new ArgumentNullException("memberExpression");
        }
        var body = memberExpression.Body as MemberExpression;
        if (body == null)
        {
            throw new ArgumentException("Lambda must return a property.");
        }

        var vmExpression = body.Expression as ConstantExpression;
        if (vmExpression != null)
        {
            LambdaExpression lambda = Expression.Lambda(vmExpression);
            Delegate vmFunc = lambda.Compile();
            object sender = vmFunc.DynamicInvoke();

            PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(body.Member.Name));
        }
    }
}

您的ViewModel看起来应该是这样的。

public class ViewModel : Notifier
{
    public ObservableCollection<String> Messages
    {
        get { return Get<ObservableCollection<String>>(); }
        set
        {
            Set(value); 
            Notify(() => AreThereMessages);
        }
    }

    public bool AreThereMessages => Messages?.Count > 0;
}

上面的Notifier类不需要任何私有变量。

Getter:get { return Get<T>(); }

Setter:get { Set(value); }

通知其他财产:Notify(() => OtherProperty);

示例视图:

<DataGrid ItemsSource="{Binding Messages}"/>
<Button IsEnabled="{Binding AreThereMessages}"/>

如果消息集合为空,则上面的代码会通知按钮。 这是我知道处理你的viewmodel而不需要额外库的最简单方法。