一、前言


在阅读本篇文章之前,最好有ICommand和INotifyPropertyChanged等基础知识。

二、BindableBase



BindableBase抽象类实现了INotifyPropertyChanged接口,主要作用当绑定到界面的数据发生改变的时候可以通知界面进行更新。

   

    public class ContentViewModel : BindableBase
    {
        private string _message;
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }
    }

三、Command


用于事件的触发。有带参数和不带参数两种。

    public class ContentViewModel : BindableBase
    {
        public DelegateCommand SendMessageCommand { get; set; }
        private bool _isEnable=true;
        public bool IsEnable
        {
            get { return _isEnable; }
            set { SetProperty<bool>(ref _isEnable, value); }
        }
        
        public ContentViewModel()
        {
            SendMessageCommand = new DelegateCommand(SendMessage).ObservesCanExecute(()=>IsEnable);
        }
    }

    

        <Button
            Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Command="{Binding SendMessageCommand}"
            Content="Clik" />


        
注意上面的写法,在实例化的时候调用了ObservesCanExecute方法,这个方法有一个Fun委托参数用来表示该命令是否可以执行(表现在界面上就是按钮灰调),调用这个方法后就不需要另外使用方法RaiseCanExecuteChanged()通知了。

另外上面的写法等价如下:

SendMessageCommand = new DelegateCommand(SendMessage,CanSendMessage).ObservesProperty(()=>IsEnable);
        private bool CanSendMessage()
        {
            return IsEnable;
        }


带参数的命令则需要将代码改为如下:

public DelegateCommand<string> SendMessageCommand { get; set; }

SendMessageCommand = new DelegateCommand<string>(SendMessage,CanSendMessage).ObservesProperty(()=>IsEnable);
        <Button
            Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Command="{Binding SendMessageCommand}"
            CommandParameter="{Binding Message}"
            Content="Clik" />

 

四、CompositeCommand


对于单个Command而言,只能触发单个对应的功能,而复合命令是Prism当中非常强大的功能,CompositeCommand简单来说就是父命令,它可以注册N个子命令。它有两个主要特征:

  • 当父命令被激活的时候,它将触发所有的子命令
  • 只要有一个子命令CanExecute=false,那么父命令将无法被激活。


使用的时候需要使用RegisterCommand()方法进行注册子命令。

五、事件聚合器IEventAggregator


5.1 IEventAggregator接口

    //
    // 摘要:
    //     Defines an interface to get instances of an event type.
    public interface IEventAggregator
    {
        //
        // 摘要:
        //     Gets an instance of an event type.
        //
        // 类型参数:
        //   TEventType:
        //     The type of event to get.
        //
        // 返回结果:
        //     An instance of an event object of type TEventType.
        TEventType GetEvent<TEventType>() where TEventType : EventBase, new();
    }


 
该接口只有一个方法。该方法是一个泛型方法,该泛型类型需要继承自EventBase。Prism中已经预定义了这么一个类:PubSubEvent 。


首先自定义一个MessageSentEvent类,继承自PubSubEvent。注意,因为这个类肯定会在多个Module中使用到,所以最好单独建立一个项目,然后子模块分别引用。

    public class MessageSendEvent : PubSubEvent<string>
    {

    }

   
在子模块中,首先要注入IEventAggregator的实现,这个只需要在构造函数中注入即可,因为Ioc容易会自动注入。

        private IEventAggregator ea;
        public MenuViewModel(IEventAggregator ea)
        {
            this.ea = ea;
        }

       


然后发布消息的可以使用如下代码:

 

 ea.GetEvent<MessageSendEvent>().Publish(Message);


接收端代码如下:

   

    public class ContentViewModel : BindableBase
    {
        private ObservableCollection<string> messages=new ObservableCollection<string>();
        public ObservableCollection<string> Messages 
        {
            get { return messages; }
            set { SetProperty(ref messages, value); }
        }
        private IEventAggregator ea;
        public ContentViewModel(IEventAggregator ea)
        {
            this.ea = ea;

            ea.GetEvent<MessageSendEvent>().Subscribe(RecvMessages);
        }

        private void RecvMessages(string msg)
        {
            Messages.Add(msg);
        }
    }


当然,订阅了之后也是可以取消订阅的。

ea.GetEvent<MessageSendEvent>().Unsubscribe(RecvMessages);


5.2 Subscribe
关于Subscribe函数,有几个重载,其中参数最多的有4个:

  • action: 发布事件时执行的委托。
  • ThreadOption枚举: 指定在哪个线程上接收委托回
  • KeepSubscriberReferenceAlive: 如果为true,则Prism.Events.PubSubEvent保留对订阅者的引用因此它不会收集垃圾。
  • filter: 进行筛选以评估订阅者是否应接收事件。是一个Predicate委托,结果为true时才接收。

 ea.GetEvent<MessageSendEvent>().Subscribe(RecvMessages, ThreadOption.PublisherThread, false, msg => !msg.Contains("fuck"));