• Prism程序入口、View ViewModel关联、数据绑定、数据校验、cmd


    Prism程序入口、View ViewModel关联、数据绑定、数据校验、cmd

    这是一篇朝夕Jovan老师讲Prism的课堂学习笔记。

    关于Prism框架

    Prism.Core:【Prism.dll】实现MVVM的核心功能,属于一个与平台无关的项目

    Prism.Wpf:【Prism.Wpf】包含了DialogService,Region,Module,Navigation,其他的一些WPF的功能

    Prism.Unity:【Prism.Unity.Wpf】,IOC容器

    Prism.Unity=>Prism.Wpf=>Prism.Core

    创建启动程序

    第一种初始化方式:8.0版本以前只能使用PrismBootstrapper

    1. 添加启动类:Bootstrapper
    public class Bootstrapper : PrismBootstrapper
    {
      protected override DependencyObject CreateShell()
      {        
          return Container.Resolve<FirstWindow>();
      }
    
      protected override void RegisterTypes(IContainerRegistry containerRegistry)
      {
          
      }
    }
    
    1. 修改App.cs
    public partial class App
    {
    	protected override void OnStartup(StartupEventArgs e)
      {
      base.OnStartup(e);
    
      var bs = new Bootstrapper();
      bs.Run();
      }  
    }
    

    第二种初始化方式:8.0版本开始提供一种新的方式PrismApplication【全局资源管控,项目启动】

    两者类似,只不过把Bootstrapper类的东西,拿到App.cs实现

    1. App.xaml 中删除程序的入口:StartupUrl="Main.xaml"
    2. App.xaml 中引入Prism名称空间
    <prism:PrismApplication x:Class="PrismLesson.App"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:local="clr-namespace:Zhaoxi.PrismLesson"
               xmlns:prism="http://prismlibrary.com/"
               >
      <Application.Resources>
    
      </Application.Resources>
    </prism:PrismApplication>
    
    1. 修改App.cs,继承PrismApplication,并重写CreateShell方法
    public partial class App : PrismApplication
    {
      protected override Window CreateShell()
    	{
      return Container.Resolve<FirstWindow>();
    	}
    
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    	{
    
    	}
    }
    

    View与ViewModel的多种关联方法

    使用方法

    1. View中引入名称空间:xmlns:prism="http://prismlibrary.com/"
    2. 设置为自动关联:prism:ViewModelLocator.AutoWireViewModel="True"

    注意事项:

    1. 必须是Views和ViewModels目录
    2. 需要保证命名规范的正确性
      1. View可以以View结尾,也可以不写。
      2. ViewModel必须以View的名称+”ViewModel”进行命名

    自定义ViewModel文件后缀规则

    App.cs 中重写ConfigureViewModelLocator方法

    1. View的名字
    2. 在那个名称空间
    3. ViewModel的名字
    protected override void ConfigureViewModelLocator()
    {
        base.ConfigureViewModelLocator();
    
        //自定义ViewModel文件后缀,自动匹配
        //第一种方式
        //ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) => 
        //{
        	//两个参数表示在那个名称空间
        //    var viewName = viewType.FullName.Replace("YtViews","YtViewmodels");
        //    var viewAssemblyName = viewType.GetType().Assembly.FullName;
        //    var viewModelName = $"{viewName}VM,{viewAssemblyName}";    
        //    return Type.GetType(viewModelName);
        //});
    
        //一对一注册的多种方式 01
        //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(),typeof(MainWindowViewModel));
    
        //02
        //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), 
        //    () =>Container.Resolve<MainWindowViewModel>()
        //);
    
        //03
        //ViewModeegisterlLocationProvider.R<MainWindow,M>();ainWindowViewModel
    }
    

    一对一注册

    三种代码注册方式:第三种方式最为简洁,使用1对1注册的时候,就可以取消掉prism:ViewModelLocator.AutoWireViewModel="True"

    protected override void ConfigureViewModelLocator()
    {
        base.ConfigureViewModelLocator();
        //01 第一种方式
        ViewModelLocationProvider.Register(typeof(FirstWindow).ToString(), typeof(FirstWindowVM));
          //02
        //ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), 
        //    () =>Container.Resolve<MainWindowViewModel>()
        //);
    
        //03
        //ViewModelLocationProvider.Register<FirstWindow, FirstWindowVM>();   
    }
    

    Xaml注册方式

    1. 引入命名空间:xmlns:vm="clr-namespace:Zhaoxi.PrismLesson.ZxViewModels"
    2. 设置关联
    <Window.DataContext>
        <prism:ContainerProvider Type="{x:Type vm:FirstWindowVM}"/>
    </Window.DataContext>
    

    MVVM数据属性的多种方式

    1. 继承BindableBase
    2. 实现数据绑定

    第一种方式:RaisePropertyChanged()

    public string MyProperty
    {
        get { return myVar; }
        set
        {
            myVar = value;        
            //this.RaisePropertyChanged();
            //改变的时候通知其他属性
            this.RaisePropertyChanged("其他属性名称");        
        }
    }
    

    第二种方式:SetProperty

    写了SetProperty,就可以删除 myVar = value,因为ref.

    //思考:为什么不直接在这里写值改变后的处理,SetProperty方法内的回调对值是否改变做了判断,只有真正改变了才会执行回调,直接写SetProperty后面,则每次无论是否改变成功都会执行。

    public string MyProperty
    {
        get { return myVar; }
        set
        {       
            // 第二种方式
    		//this.SetProperty(ref myVar, value, "MyProperty");
            
            //多了一个回调,变化之后调用
    		this.SetProperty<string>(ref myVar, value,
        		() =>
        		{
            		//  onChanged
        		});
    
    		//思考:为什么不直接在这里写值改变后的处理,SetProperty方法内的回调对值是否改变做了判断,只有真正改变了才会执行回调,直接写SetProperty后面,则每次无论是否改变成功都会执行。
        }
    }
    

    MVVM数据验证

    1. 继承INotifyDataErrorInfo接口,实现接口:
    public class FirstWindowVM : BindableBase, INotifyDataErrorInfo
    {
        /// <summary>
        ///  INotifyDataErrorInfo 接口方法
        /// </summary>
        //
        //错误变化 错误属性中调用这个事件    
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        //检查是否有错误
        public bool HasErrors => ErrorsContainer.HasErrors;
       	//获取错误
        public IEnumerable GetErrors(string propertyName) => ErrorsContainer.GetErrors(propertyName);
    }
    
    1. 实现一个ErrorsContainer属性
    //OnPropertyChanged;
    //    CanExecuteChanged;
    private ErrorsContainer<string> errorsContainer;
    
    public ErrorsContainer<string> ErrorsContainer
    {
        get
        {
            if (errorsContainer == null)
                errorsContainer = new ErrorsContainer<string>((propName) =>
                {
                    // 异常信息的处理
                    ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propName));
                });
    
            return errorsContainer;
        }
        set { errorsContainer = value; }
    }
    
    1. 对数据进行错误处理
    public string MyProperty
    {
        get { return myVar; }
        set
        {
            this.SetProperty(ref myVar, value, "MyProperty");
    
            if (value == "1231")
            {
                // 异常消息
                ErrorsContainer.SetErrors("MyProperty", new string[] { "输入值无效1231231" });
            }
            else
            {
                ErrorsContainer.ClearErrors("MyProperty");
            }
        }
    }
    
    1. UI错误提示样式
    <Window.Resources>
        <ControlTemplate TargetType="{x:Type TextBox}" x:Key="ct">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                    </Grid.RowDefinitions>
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                    Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
                    CornerRadius="5">
                        <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
                              VerticalContentAlignment="Center" Margin="3,5" BorderThickness="0"/>
                    </Border>
    
                    <TextBlock Grid.Row="1" Text="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox,Mode=FindAncestor}}" 
                       Foreground="Red" Margin="10,5"
                       Name="txtError"/>
    
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="Validation.HasError" Value="True">
                        <Setter Property="Visibility" Value="Visible" TargetName="txtError"/>
                        <Setter Property="ToolTip" 
                        Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
    </Window.Resources>
    <Grid>
        <StackPanel Margin="30">
            <TextBox Text="{Binding MyProperty,UpdateSourceTrigger=PropertyChanged}" FontSize="30"
                     Template="{StaticResource ct}"/>
            <TextBlock Text="{Binding MyProperty}" FontSize="30"/>
        </StackPanel>
    </Grid>
    

    MVVM命令的多种方式

    语法糖

    1. cmd 基本使用
    private DelegateCommand _fieldName;
    public DelegateCommand CommandName =>
        _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName));
    
    void ExecuteCommandName()
    {
    
    }
    
    1. cmdfull
    private DelegateCommand _fieldName;
    public DelegateCommand CommandName =>
        _fieldName ?? (_fieldName = new DelegateCommand(ExecuteCommandName, CanExecuteCommandName));
    
    void ExecuteCommandName()
    {
    
    }
    bool CanExecuteCommandName()
    {
        return true;
    }
    
    
    1. cmdg
    private DelegateCommand<string> _fieldName;
    public DelegateCommand<string> CommandName =>
        _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName));
    
    void ExecuteCommandName(string parameter)
    {
    
    }
    
    1. cmdgfull
    private DelegateCommand<string> _fieldName;
    public DelegateCommand<string> CommandName =>
        _fieldName ?? (_fieldName = new DelegateCommand<string>(ExecuteCommandName, CanExecuteCommandName));
    
    void ExecuteCommandName(string parameter)
    {
    
    }
    
    bool CanExecuteCommandName(string parameter)
    {
        return true;
    }
    

    基础使用

    传统方式挂载执行委托、检查可执行委托。

    默认直接执行cmd

    1. 继承基类DelegateCommand
    2. 实现命令属性
    private DelegateCommand _changeValue;
    public DelegateCommand ChangeValue
    {
        get
        {
            if (_changeValue == null)
        		_changeValue = new DelegateCommand(DoChangeValue);
            return _changeValue;
        }
        set{_changeValue = value;}
    }
    private void DoChangeValue()
    {
        this.Value == "1231";
    }
    

    默认判断是否执行cmd

    IsCan为true,才可以执行命令。

    private DelegateCommand _changeValue;
    public DelegateCommand ChangeValue
    {
        get
        {
            if (_changeValue == null)
        		_changeValue = new DelegateCommand(DoChangeValue, DoCanChangeValue);
            return _changeValue;
        }
        set{_changeValue = value;}
    }
    // 判断命令相关按钮是否可执行
    private bool DoCanChangeValue()
    {
        return IsCan;
    }
    
    // 命令执行体
    private void DoChangeValue(string param)
    {
        this.Value = "456";
    }
    
    private bool _isCan;
    
    public bool IsCan
    {
        get { return _isCan; }
        set
        {
            SetProperty(ref _isCan, value);
            ChangeValue.RaiseCanExecuteChanged();
        }
    } 
    

    监控属性变化,执行cmd

    1. 监控某个属性是否变化,如果变化出发cmd。

    2. 使用DelegateCommand对象的ObservesProperty方法,不需要ChangeValue.RaiseCanExecuteChanged()。

    ObservesCanExecute监控的是某个属性的变化,而不是某个值。属性变化的时候Prism内部触发了ChangeValue.RaiseCanExecuteChanged()

    精简版

    if (_changeValue == null)
    {
        _changeValue = new DelegateCommand(DoChangeValue, DoCanChangeValue);     
        //观察一个属性,当这个属性变化的时候触发DoCanChangeValue
        _changeValue.ObservesProperty(() => Value);
    }
    

    详细版

    private string _value;
    public string Value
    {
        get { return _value; }
        set { SetProperty<string>(ref _value, value); }
    }
    
    private DelegateCommand _changeValue;
    public DelegateCommand ChangeValue
    {
        get
        {
            if (_changeValue == null)
            {
                _changeValue = new DelegateCommand(DoChangeValue,DoCanChangeValue).ObservesCanExecute(() => Value);
            }
    
            return _changeValue;
        }
    }
    
    //判断命令相关按钮是否可执行
    private bool DoCanChangeValue()
    {
        return IsCan;    
    }
    
    //命令执行体
    private void DoChangeValue()
    {
        this.Value = "456";
    }
    
    private string _value;
    
    public string Value
    {
        get { return _value; }
        set { SetProperty<string>(ref _value, value); }
    }
    
    

    监控属性是否为true,执行cmd,可以省略大量代码,但有局限性。

    通过ObservesCanExecute观察属性是否为true,如果为true则执行cmd.可以删除DoCanChangeValue回调。

    简化了DoCanChangeValue,但是功能性少了多了局限性。

    精简版

    if (_changeValue == null)
    {
        _changeValue = new DelegateCommand(DoChangeValue);
        _changeValue.ObservesCanExecute(() => IsCan);
    }
    

    详细版

    private string _value;
    public string Value
    {
        get { return _value; }
        set { SetProperty<string>(ref _value, value); }
    }
    
    private DelegateCommand _changeValue;
    public DelegateCommand ChangeValue
    {
        get
        {
            if (_changeValue == null)
            {
                _changeValue = new DelegateCommand(DoChangeValue).ObservesCanExecute(() => IsCan);
            }
            return _changeValue;
        }
    }
    
    //命令执行体
    private void DoChangeValue()
    {
        this.Value = "456";
    }
    
    private bool _isCan;
    
    public bool IsCan
    {
        get { return _isCan; }
        set
        {
            SetProperty(ref _isCan, value);
        }
    }
    

    带参数的cmd

    int型,Prism会有错误提示,MvvmLight没有提示。

    简化版

    private DelegateCommand<string> _changeValue;
    public DelegateCommand<string> ChangeValue
    {
        get
        {
             if (_changeValue == null)
             {
                 _changeValue = new DelegateCommand<string>(DoChangeValue);
                 _changeValue.ObservesCanExecute(() => IsCan);
             }
    
             return _changeValue;
         }
     }
    
    //普通
    private void DoChangeValue(string param)
    {
        this.Value = "456";
    }
    
    if (_changeValue == null)
    {
        _changeValue = new DelegateCommand<string>(DoChangeValue);
        _changeValue.ObservesCanExecute(() => IsCan);
    }
    
    <Button Content="Button" FontSize="30" Command="{Binding ChangeValue}" CommandParameter="123"/>
    

    普通详细版

    private string _value;
    public string Value
    {
        get { return _value; }
        set { SetProperty<string>(ref _value, value); }
    }
    
    private DelegateCommand<string> _changeValue;
    public DelegateCommand<string> ChangeValue
    {
        get
        {
            if (_changeValue == null)
            {
                _changeValue = new DelegateCommand<string>		(DoChangeValue).ObservesCanExecute(() => IsCan);
            return _changeValue;
        }
    }
    
    //命令执行体
    private void DoChangeValue(string param)
    {
        this.Value = "param";
    }
    
    private bool _isCan;
    
    public bool IsCan
    {
        get { return _isCan; }
        set
        {
            SetProperty(ref _isCan, value);
        }
    }
    

    异步命令

    简化版

    //异步
    if (_changeValue == null)
    {
        _changeValue = new DelegateCommand<string>(async (o) => await DoChangeValue(o));
        _changeValue.ObservesCanExecute(() => IsCan);
    }
    
    private async Task DoChangeValue(string param)
    {
        await Task.Delay(1000);
        this.Value = "456";
    }
    

    详细版

    private string _value;
    public string Value
    {
        get { return _value; }
        set { SetProperty<string>(ref _value, value); }
    }
    
    private DelegateCommand<string> _changeValue;
    public DelegateCommand<string> ChangeValue
    {
        get
        {
            if (_changeValue == null)
            {
                _changeValue = new DelegateCommand<string>(async (param) => await DoChangeValue(param)).ObservesCanExecute(() => IsCan);
    
            return _changeValue;
        }
    }
    
    //命令执行体
    private async Task DoChangeValue(string param)
    {
        await Task.Delay(1000);
        this.Value = "param";
    }
    
    private bool _isCan;
    
    public bool IsCan
    {
        get { return _isCan; }
        set
        {
            SetProperty(ref _isCan, value);
        }
    }
    

    事件绑定Command,事件参数传值

    1. 引用InteractivityInteraction两个库中的一个,Prism默认继承InteractivityInteraction库,xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

    2. 一般不会在Button中使用,实际是向没有Command属性的对象事件进行绑定,例如TextBox。

    3. 参数类型:如果是Source就是把事件源对象传进来,还有多种参数类型可以F12跟进去看函数定义。

    4. 传递事件常见的e参数:删除TriggerParameterPath,默认传递的就是e参数

    <TextBox FontSize="30" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <!--  如果需要传EventArgs参数的话,可以将TriggerParameterPath移除,不指定  -->
                <prism:InvokeCommandAction Command="{Binding EventCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>
    

    xaml

    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    
    <Button Content="Button - Event" FontSize="30">
        <!--利用Button的Click事件做演示,实际是向没有Command属性的对象事件进行绑定-->
        <!--InteractivityInteraction-->
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <!--如果需要传EventArgs参数的话,可以将TriggerParameterPath移除,不指定-->
                <prism:InvokeCommandAction Command="{Binding EventCommand}"/>
                <!--<prism:InvokeCommandAction Command="{Binding EventCommand}" TriggerParameterPath="Source"/>-->
    
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    
    private DelegateCommand<object> _eventCommand;
    
    public DelegateCommand<object> EventCommand
    {
        get
        {
            if (_eventCommand == null)
            {
                _eventCommand = new DelegateCommand<object>((o) =>
                {
    				//接收到的事件参数
                });
            }
            return _eventCommand;
        }
    }
    

    事件聚合器、弹出自定义窗口

    精简版

    事件订阅、发布的一个过程。

    1. 定义一个基本消息类型MessageEvent,继承PubSubEvent
    2. 声明IEventAggregator 类型字段
    3. 构造函数中注入一个IEventAggregator
    4. 订阅消息事件

    执行命令以后,事件执行。

    主要是通过 _ea.GetEvent<PubSubEvent>().Subscribe(DoMessage);中的PubSubEvent判断的,所以才需要创建单独的类,甚至是空类,主要是为了方便区分。

    public class MessageEvent : PubSubEvent<string>
    {
    }
    
    IEventAggregator _ea;
    
    public FirstWindowViewModel(IEventAggregator ea)
    {
        this.Value = "123";
    
        _ea = ea;
        // 订阅一个消息事件
        _ea.GetEvent<PubSubEvent<string>>().Subscribe(DoMessage);
    }
    
    private void DoMessage(string msg)
    {
        
    }
    
    private DelegateCommand _eventCommand;
    
    public DelegateCommand EventCommand
    {
        get
        {
            if (_eventCommand == null)
            {
                _eventCommand = new DelegateCommand<object>(() =>
                {
                    //弹出窗口
                    //自定义窗口
                    //发布
                    _ea.GetEvent<PubSubEvent<string>>().Publish("123");
                });
            }
           return _eventCommand;
        }
    }
    
    
    keepSubscriberReferenceAlive参数控制是否为弱引用

    keepSubscriberReferenceAlive:订阅事件属于一个弱引用。

    1. 如果是false,不需要管取消订阅,默认为false.
    2. 如果是true,手动处理取消订阅
    ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1,keepSubscriberReferenceAlive: false);
    
    // 取消订立,如果 keepSubscriberReferenceAlive 为False或默认值 不需要取消订阅
    //ea.GetEvent<MessageEvent1>().Unsubscribe(DoMessage1);
    
    ThreadOption.PublisherThread参数控制线程的
    1. PublisherThread = 0, 默认是PublisherThread

    2. UIThread = 1,

    3. BackgroundThread = 2

    ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false);
    
    Predicate 对消息进行过滤Filter

    对发布的事件传过来的参数进行过滤,满足要求的才会出发事件。

    ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false, DoFilter);
    
    private bool DoFilter(string msg)
    {
        return msg.Contains("12");
    }
    

    详细版

    xaml代码

    <Button
            Command="{Binding Command}"
            CommandParameter="123"
            Content="Button 事件聚合触发"
            FontSize="30" />
    <ItemsControl FontSize="30" ItemsSource="{Binding ValueList}" />
    

    01 继承PubSubEvent

    public class MessageEvent : PubSubEvent<string>
    {
        public int MyProperty { get; set; }
    }
    
    public class MessageEvent1 : PubSubEvent<string>
    {
    }
    

    02 订阅

    private ObservableCollection<string> _valueList;
    
    public ObservableCollection<string> ValueList
    {
        get { return _valueList ?? (_valueList = new ObservableCollection<string>()); }
        set { _valueList = value; }
    }
    
    
    IEventAggregator _ea;
    public FirstWindowViewModel(IEventAggregator ea, IContainerExtension containerRegistry)
    {
        this.Value = "123";
    
        _ea = ea;
        // 订阅一个消息事件
        //ea.GetEvent<PubSubEvent<string>>().Subscribe(DoMessage);
        var me = ea.GetEvent<MessageEvent>();
        me.Subscribe(DoMessage);
        me.MyProperty = 123;
    
        /// ThreadOption,,默认PublisherThread,管理订立消息的执行线程
        /// keepSubscriberReferenceAlive:订阅事件属于一个弱引用
        /// Filter  消息过滤 ,如果回调返回True,才执行消息体,否则不处理此消息
        //ThreadOption.PublisherThread控制线程的,本案例中配合ValueList和ItemsControl
        ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.PublisherThread, keepSubscriberReferenceAlive: false, DoFilter);
    
        //指定在UI线程执行
        //ea.GetEvent<MessageEvent1>().Subscribe(DoMessage1, ThreadOption.UIThread, keepSubscriberReferenceAlive: false, DoFilter);
        // 取消订立,如果 keepSubscriberReferenceAlive 为False或默认值 不需要取消订阅
        //ea.GetEvent<MessageEvent1>().Unsubscribe(DoMessage1);
    }
    
    private void DoMessage(string msg)
    {
    
    }
    //UI线程执行
    //private void DoMessage(string msg)
    //{
    	//ValueList.Add("123");
    //}
    
    private bool DoFilter(string msg)
    {
        return msg.Contains("12");
    }
    
    

    03 发布

    private DelegateCommand _command;
    
    public DelegateCommand Command
    {
        get
        {
            if (_command == null)
            {
                _command = new DelegateCommand(() =>
                {
                    // 弹出窗口
                    // 通过事件聚合器弹出自定义窗口
                    // 而不是普通的类似MvvmLight中的 Messenger  Token   Type
    
                    //_ea.GetEvent<PubSubEvent<string>>().Publish("123");
                    //_ea.GetEvent<MessageEvent>().Publish("123");
    
                    
                    var value = _ea.GetEvent<MessageEvent>().MyProperty;
                    _ea.GetEvent<MessageEvent1>().Publish("123");
                    _ea.GetEvent<MessageEvent1>().Publish("456");
                    _ea.GetEvent<MessageEvent1>().Publish("123");
                    //Task.Run(() =>
                    //{
                    //    _ea.GetEvent<MessageEvent1>().Publish("123");
                    //});
                });
            }
            return _command;
        }
    }
    

    复合命令

    一个按钮,把所有相同的复合命令执行一遍。比如:保存按钮,把所有内容保存。

    每个页面出发单独的保存,还有个隐藏功能,所有的命令都有个是否可执行的方法,如果设置了,那么只有所有按钮都可以执行以后,它才可以执行。

    1. 添加一个程序集,需要我们自定义一个接口,把它改成类库。这样复合命令就实现好了
    public interface ICompositeCommands
    {
        CompositeCommand DoCommand { get; }
    }
    
    public class CompositeCommands : ICompositeCommands
    {
        private CompositeCommand _doCommand = new CompositeCommand();
        public CompositeCommand DoCommand
        {
            get { return _doCommand; }
        }
    }
    
    1. App.xaml.cs中的RegisterTypes 注入
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        // 注册复合命令
        containerRegistry.RegisterSingleton<ICompositeCommands, CompositeCommands>();
    }
    
    1. 创建一个按钮,xaml
    <Grid>
        <StackPanel>
            <TextBlock Text="HeaderView" FontSize="30"/>
            <Button Content="Button" FontSize="30" Command="{Binding CompositeCommands.DoCommand}"/>
        </StackPanel>
    </Grid>
    
    1. 创建对应的ViewModule
    public class HeaderViewModel : BindableBase
    {
        private ICompositeCommands _compositeCommand;
    
        public ICompositeCommands CompositeCommands
        {
            get { return _compositeCommand; }
            set { SetProperty(ref _compositeCommand, value); }
        }
    
        public HeaderViewModel(ICompositeCommands compositeCommands)
        {
            CompositeCommands = compositeCommands;
        }
    }
    
    1. 构造函数注入ICompositeCommands,将command注册到复合命令集合中。
    public DelegateCommand SaveCommand { get; private set; } 
    public MenuManagementViewModel(ICompositeCommands compositeCommands)
    {
         SaveCommand = new DelegateCommand(() =>
            {
                // 菜单保存
            });
    	 compositeCommands.DoCommand.RegisterCommand(SaveCommand);
    }
    
    登峰造极的成就源于自律
  • 相关阅读:
    keyset与entryset
    solr4.9r+ Eclipse 4.3+ tomcat 7.5 +winds7(二)
    如何解决This system is not registered with RHN.
    堆和栈的差别(转过无数次的文章)
    墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律
    atitit.软件开发GUI 布局管理优缺点总结java swing wpf web html c++ qt php asp.net winform
    漫谈并发编程(二):java线程的创建与基本控制
    exosip
    PostgreSQL服务端监听设置及client连接方法
    APK反编译。
  • 原文地址:https://www.cnblogs.com/fishpond816/p/15216765.html
Copyright © 2020-2023  润新知