zoukankan      html  css  js  c++  java
  • 从PRISM开始学WPF(六)MVVM(二)Command-更新至Prism7.1

    命令绑定(Command)

    [7.1updated]这一节除了基础app部分,并没有什么变化

    什么是Command?

    先看下微软官方的说明:

    Commanding is an input mechanism in Windows Presentation Foundation (WPF) which provides input handling at a more semantic level than device input. Examples of commands are the Copy, Cut, and Paste operations found on many applications.

    虽然英语捉鸡,但是不妨碍我们阅读一手资料,燃鹅(●'◡'●),我们看下Google的翻译:

    指令是Windows Presentation Foundation(WPF)中的一种输入机制,它提供比设备输入更多语义级别的输入处理。命令的例子是在许多应用程序中找到的复制剪切粘贴操作。

    好像也没什么用!还是直接拿例子来看:

    MainWindow.xaml

    <Window x:Class="UsingDelegateCommands.Views.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:prism="http://prismlibrary.com/"
            prism:ViewModelLocator.AutoWireViewModel="True"
            Title="Using DelegateCommand" Width="350" Height="275">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <CheckBox IsChecked="{Binding IsEnabled}" Content="Can Execute Command" Margin="10"/>
            <Button Command="{Binding ExecuteDelegateCommand}" Content="DelegateCommand" Margin="10"/>
            <Button Command="{Binding DelegateCommandObservesProperty}" Content="DelegateCommand ObservesProperty" Margin="10"/>
            <Button Command="{Binding DelegateCommandObservesCanExecute}" Content="DelegateCommand ObservesCanExecute" Margin="10"/>
            <Button Command="{Binding ExecuteGenericDelegateCommand}" CommandParameter="Passed Parameter" Content="DelegateCommand Generic" Margin="10"/>
            <TextBlock Text="{Binding UpdateText}" Margin="10" FontSize="22"/>
        </StackPanel>
    </Window>
    
    

    MainWindowViewModel.cs

    using System;
    using Prism.Commands;
    using Prism.Mvvm;
    
    namespace UsingDelegateCommands.ViewModels
    {
        public class MainWindowViewModel : BindableBase
        {
            private bool _isEnabled;
            public bool IsEnabled
            {
                get { return _isEnabled; }
                set
                {
                    SetProperty(ref _isEnabled, value);
                    ExecuteDelegateCommand.RaiseCanExecuteChanged();
                }
            }
    
            private string _updateText;
            public string UpdateText
            {
                get { return _updateText; }
                set { SetProperty(ref _updateText, value); }
            }
    
            public DelegateCommand ExecuteDelegateCommand { get; private set; }
    
            public DelegateCommand<string> ExecuteGenericDelegateCommand { get; private set; }
    
            public DelegateCommand DelegateCommandObservesProperty { get; private set; }
    
            public DelegateCommand DelegateCommandObservesCanExecute { get; private set; }
    
    
            public MainWindowViewModel()
            {
                ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
    
                DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute)
                    .ObservesProperty(() => IsEnabled);
    
                DelegateCommandObservesCanExecute = new DelegateCommand(Execute)
                    .ObservesCanExecute(() => IsEnabled);
    
                ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric)
                    .ObservesCanExecute(() => IsEnabled);
            }
    
            private void Execute()
            {
                UpdateText = $"Updated: {DateTime.Now}";
            }
    
            private void ExecuteGeneric(string parameter)
            {
                UpdateText = parameter;
            }
    
            private bool CanExecute()
            {
                return IsEnabled;
            }
        }
    }
    
    

    View部分:

    头部引入命名空间,指定ViewModeLocator模式:

    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True"
    

    接着是一个:

        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        </StackPanel>
    

    接着内部是一组控件,一个CheckBox四个Button一个 TextBlock。

    • CheckBox IsChecked="{Binding IsEnabled}"

    复选框的勾选状态绑定到一个布尔型属性上。

    • Button Command="{Binding ExecuteDelegateCommand}"

    普通命令绑定

    • Button Command="{Binding ExecuteGenericDelegateCommand}" CommandParameter="Passed Parameter"

    带参数的 命令绑定

    • TextBlock Text="{Binding UpdateText}"

    为TextBlock的Text属性绑定数据源

    Tips

    Binding语法 Property="{Binding PropertyPath}",PropertyPath就是VM

    当为Command进行Binding的时候,还可以带参数,使用CommandParameter属性,上面的CommandParameter指定了一个字符串“Passed Parameter”,当然还可以为其Binding一个对象。

    ViewModel部分:

    set方法中的:

    SetProperty(ref _isEnabled, value);
    

    属性变更的通知,当视图状态更新后,会通知VM更改_isEnabled

    ExecuteDelegateCommand.RaiseCanExecuteChanged();
    

    这段代码,则会通知ExecuteDelegateCommand的可执行状态更改了,让他重新获取下可执行状态,那他是怎么获取可执行状态的呢?我们看下这个Command:

    ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);
    

    new 的时候,有两个参数,第一个是Action(无返回类型的方法)Execute(需要执行的方法),第二个是一个Func,就是一个返回布尔型的方法CanExecute来获取command的可执行状态,当上面通知他可执行状态变更后,他就会重新调用CanExecute方法来获取目前的可执行状态(也就是按钮的可按下状态),来看下这个方法:

    private bool CanExecute()
    {
         return IsEnabled;
    }
    

    很简单,直接返回了IsEnabled,而他是跟视图的CheckBox的IsChecked绑定的,当然也可以返回_isEnabled,而我更倾向后面这个,Public那个是给外人用的,蛤蛤。

    当然可执行状态,还有其他的更优雅的写法,也就不用写ExecuteDelegateCommand.RaiseCanExecuteChanged();了,具体代码如下:

                DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute)
                    .ObservesProperty(() => IsEnabled);
    
                DelegateCommandObservesCanExecute = new DelegateCommand(Execute)
                    .ObservesCanExecute(() => IsEnabled);
    

    下面这个是带参数的命令(command),他的回调函数需要一个string类型的参数,在new的时候要指定入参类型:

                ExecuteGenericDelegateCommand = new DelegateCommand<string>(ExecuteGeneric)
                    .ObservesCanExecute(() => IsEnabled);
    

    回调函数ExecuteGeneric:

            private void ExecuteGeneric(string parameter)
            {
                UpdateText = parameter;
            }
    

    总结:

    ViewModel(简称VM,下文也偶尔会出现VM,也指ViewModel)的类需要继承BindableBase,BindableBase实现了INotifyPropertyChanged接口。

    命令类型是DelegateCommand,这继承自DelegateCommandBase,而DelegateCommandBase实现了ICommand接口。

    这俩接口是MVVM的底层接口。有兴趣的可以看一下 MVVMFoundation,他封装没有那么多次,只有四个cs文件,可以直接看到,他是如何运用ICommand和INotifyPropertyChanged接口的。
    有兴趣的可以看一下浅谈WPF中的MVVM框架--MVVMFoundation
    但是,作为高级的我们,就用高级的封装,有了火柴谁还燧木取火,233333

    复合型命令绑定

    通常情况下,我们的命令调用者直接调用我们的命令,但是有些时候,我们需要从外部(比如其他的视图或父视图)的控件调用该命令,那么就需要一个CompositeCommand

    CompositeCommand是一个由多个子命令组成的命令。它提供了执行子命令的所有关联方法(ExecuteCanExecute)的功能,当所有子命令的可执行状态为True的时候CompositeCommand才可以被执行。

  • 相关阅读:
    第五周:函数
    第四周:循环控制
    第三周:循环
    第二周:判断
    第一周:简单的计算程序
    cocos2dx-lua采用pbc解析proto问题修正
    cocos2dx 3.9.1 mac模拟器log输出bug修正
    基于dragonbones的cocos2dx lua封装
    EF 3.0 要开启 数据库连接复用 MultipleActiveResultSets=true
    找不到资产文件“xxxxobjproject.assets.json
  • 原文地址:https://www.cnblogs.com/hicolin/p/8694940.html
Copyright © 2011-2022 走看看