• MVVMLight学习笔记(五)RelayCommand深究


    一、概述

    有时候,单纯的命令绑定不一定能满足我们的开发需求,比如我们需要在命令绑定的时候传递一个参数,这个时候,我们就需要使用RelayCommand的泛型版本了。

    RelayCommand的泛型版本的构造函数以下:

    public RelayCommand(Action<T> execute, bool keepTargetAlive = false);
    public RelayCommand(Action<T> execute, Func<T, bool> canExecute, bool keepTargetAlive = false);

    构造函数传入的是委托类型的参数,Execute 和 CanExecute执行委托方法。

    二、带一个参数的命令绑定

    代码片段如下:

    复制代码
    <StackPanel>
                <GroupBox Header="带string类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserList:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <Label Content="{Binding Path=UserList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="20" />
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserName:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <TextBox Width="200" Name="tbUser"></TextBox>
                            <Button Content="AddUser" Command="{Binding AddUserCommand}" CommandParameter="{Binding ElementName=tbUser,Path=Text}"></Button>
                            <CheckBox Content="IsCanAdd" VerticalAlignment="Center" FontSize="16" IsChecked="{Binding IsCanAddUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    复制代码
    复制代码
     private RelayCommand<string> addUserCommand;
    
            public RelayCommand<string> AddUserCommand
            {
                get
                {
                    if (addUserCommand == null)
                    {
                        addUserCommand = new RelayCommand<string>(AddUser, (string p) => { return IsCanAddUser; });
                    }
                    return addUserCommand;
                }
                set { addUserCommand = value; }
            }
            private void AddUser(string par)
            {
                UserList = UserList + "  " + par;
            }
    复制代码

    三、带多个参数的命令绑定

    给命令传递多个参数,建议使用以下方式:

    使用MultiBinding将多绑定的各个值转换成我们所需的对象或者实例模型,再传递给ViewModel中的命令。

    代码片段如下:

    复制代码
    <Window x:Class="MvvmLightDemo1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:MvvmLightDemo1"
            xmlns:cvt="clr-namespace:MvvmLightDemo1.Converter"
            xmlns:mvvm="http://www.galasoft.ch/mvvmlight"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="MVVMLIghtDemo1" Height="500" Width="700"  >
        <Window.Resources>
            <cvt:UserInfoConverter x:Key="userInfoConverter"></cvt:UserInfoConverter>
        </Window.Resources>
        <Window.DataContext>
            <Binding Path="Main" Source="{StaticResource Locator}"></Binding>
        </Window.DataContext>
        <StackPanel>
            <StackPanel>
                <GroupBox Header="带string类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserList:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <Label Content="{Binding Path=UserList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="20" />
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserName:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <TextBox Width="200" Name="tbUser"></TextBox>
                            <Button Content="AddUser" Command="{Binding AddUserCommand}" CommandParameter="{Binding ElementName=tbUser,Path=Text}"></Button>
                            <CheckBox Content="IsCanAdd" VerticalAlignment="Center" FontSize="16" IsChecked="{Binding IsCanAddUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
            <StackPanel>
                <GroupBox Header="带对象类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserName:" FontSize="16" ></Label>
                            <TextBox Width="200" Name="tbxUser" FontSize="16" />
                            <Label Content="Password:" FontSize="16" ></Label>
                            <TextBox Width="200" Name="tbxPwd" FontSize="16" />
                            <Button Content="AddUser" Command="{Binding AddUserCommandWithObjPar}">
                                <Button.CommandParameter>
                                    <MultiBinding Converter="{StaticResource userInfoConverter}">
                                        <Binding ElementName="tbxUser" Path="Text"/>
                                        <Binding ElementName="tbxPwd" Path="Text"/>
                                    </MultiBinding>
                                </Button.CommandParameter>
                                
                            </Button>
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="Parameter:"  FontSize="16" ></Label>
                            <Label Content="{Binding ObjParameter}"  FontSize="16" ></Label>
    
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
            <StackPanel>
                <GroupBox Header="事件转命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
                    <StackPanel>
                        <StackPanel>
                            <ListBox x:Name="lb" ItemsSource="{Binding ListBoxData}"  BorderThickness="0" SelectedIndex="{Binding SelectIndex}" >
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="SelectionChanged">
                                        <mvvm:EventToCommand Command="{Binding SelectionChangedCommand}"/>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                                <ListBox.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <WrapPanel Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/>
                                    </ItemsPanelTemplate>
                                </ListBox.ItemsPanel>
    
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <Border BorderBrush="AntiqueWhite" BorderThickness="1">
                                            <StackPanel Margin="2">
    
                                                <Image Source="{Binding Img}" Width="96" Height="96"/>
                                                <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/>
                                    
                                           
                                        </StackPanel>
                                        </Border>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>
                            <Label Content="您选择的是:" FontSize="16" ></Label>
                            <Label Content="{Binding Path=SelResult,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="16" />
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
        </StackPanel>
    </Window>
    复制代码
    复制代码
     1 using GalaSoft.MvvmLight;
     2 
     3 namespace MvvmLightDemo1.ViewModel
     4 {
     5     public class UserModel: ObservableObject
     6     {
     7         private string userName;
     8 
     9         public string UserName
    10         {
    11             get { return userName; }
    12             set
    13             {
    14                 userName = value;
    15                 RaisePropertyChanged();
    16             }
    17         }
    18 
    19         private string passWord;
    20 
    21         public string PassWord
    22         {
    23             get { return passWord; }
    24             set
    25             {
    26                 passWord = value;
    27                 RaisePropertyChanged();
    28             }
    29         }
    30 
    31 
    32     }
    33 }
    复制代码
    复制代码
    using MvvmLightDemo1.ViewModel;
    using System;
    using System.Linq;
    using System.Windows.Data;
    
    namespace MvvmLightDemo1.Converter
    {
        public class UserInfoConverter: IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (!values.Cast<string>().Any(text => string.IsNullOrEmpty(text)) && values.Count() == 2)
                {
                    UserModel userModel = new UserModel() { UserName = values[0].ToString(), PassWord = values[1].ToString()};
                    return userModel;
                }
    
                return null;
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    复制代码
    复制代码
       private RelayCommand<UserModel> addUserCommandWithObjPar;
    
            public RelayCommand<UserModel> AddUserCommandWithObjPar
            {
                get
                {
                    if (addUserCommandWithObjPar == null)
                    {
                        addUserCommandWithObjPar = new RelayCommand<UserModel>(AddUserWithObjPar);
                    }
                    return addUserCommandWithObjPar;
                }
                set { addUserCommandWithObjPar = value; }
            }
            private void AddUserWithObjPar(UserModel par)
            {
                ObjParameter = "UserName: "+ par.UserName + " Password: " + par.PassWord;
            }
    复制代码

    后记:

    从MVVM的模式来说,其实命令中的参数传递未必是必要的。与其维护一段额外的参数代码,还不如把所有的交互参数细化成为当前DataContext下的全局属性。View开发人员和ViewModel开发人员共同维护好这份命令清单和属性清单即可。

    四、EventToCommand

    在WPF中,并不是所有控件都有Command,例如TextBox,那么当文本改变,我们需要处理一些逻辑,这些逻辑在ViewModel中,没有Command如何绑定呢?

    这个时候我们就用到EventToCommand,事件转命令,可以将一些事件例如TextChanged,Checked等事件转换成命令的方式。

    接下来我们就以ListBox为例子,来看看具体的实例:

    View代码:(这边声明了i特性和mvvm特性,一个是为了拥有触发器和行为附加属性的能力,当事件触发时,会去调用相应的命令,EventName代表触发的事件名称;一个是为了使用MVVMLight中 EventToCommand功能。)

    这边就是当ListBox执行SelectionChanged事件的时候,会相应去执行ViewModel中 SelectionChangedCommand命令。

    代码片段如下:

    复制代码
    <Window x:Class="MvvmLightDemo1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:MvvmLightDemo1"
            xmlns:cvt="clr-namespace:MvvmLightDemo1.Converter"
            xmlns:mvvm="http://www.galasoft.ch/mvvmlight"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="MVVMLIghtDemo1" Height="500" Width="700"  >
        <Window.Resources>
            <cvt:UserInfoConverter x:Key="userInfoConverter"></cvt:UserInfoConverter>
        </Window.Resources>
        <Window.DataContext>
            <Binding Path="Main" Source="{StaticResource Locator}"></Binding>
        </Window.DataContext>
        <StackPanel>
            <StackPanel>
                <GroupBox Header="带string类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserList:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <Label Content="{Binding Path=UserList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="20" />
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserName:" VerticalContentAlignment="Center" FontSize="20" ></Label>
                            <TextBox Width="200" Name="tbUser"></TextBox>
                            <Button Content="AddUser" Command="{Binding AddUserCommand}" CommandParameter="{Binding ElementName=tbUser,Path=Text}"></Button>
                            <CheckBox Content="IsCanAdd" VerticalAlignment="Center" FontSize="16" IsChecked="{Binding IsCanAddUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
            <StackPanel>
                <GroupBox Header="带对象类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="UserName:" FontSize="16" ></Label>
                            <TextBox Width="200" Name="tbxUser" FontSize="16" />
                            <Label Content="Password:" FontSize="16" ></Label>
                            <TextBox Width="200" Name="tbxPwd" FontSize="16" />
                            <Button Content="AddUser" Command="{Binding AddUserCommandWithObjPar}">
                                <Button.CommandParameter>
                                    <MultiBinding Converter="{StaticResource userInfoConverter}">
                                        <Binding ElementName="tbxUser" Path="Text"/>
                                        <Binding ElementName="tbxPwd" Path="Text"/>
                                    </MultiBinding>
                                </Button.CommandParameter>
                                
                            </Button>
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="Parameter:"  FontSize="16" ></Label>
                            <Label Content="{Binding ObjParameter}"  FontSize="16" ></Label>
    
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
            <StackPanel>
                <GroupBox Header="事件转命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
                    <StackPanel>
                        <StackPanel>
                            <ListBox x:Name="lb" ItemsSource="{Binding ListBoxData}"  BorderThickness="0" SelectedIndex="{Binding SelectIndex}" >
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="SelectionChanged">
                                        <mvvm:EventToCommand Command="{Binding SelectionChangedCommand}"/>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                                <ListBox.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <WrapPanel Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/>
                                    </ItemsPanelTemplate>
                                </ListBox.ItemsPanel>
    
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <Border BorderBrush="AntiqueWhite" BorderThickness="1">
                                            <StackPanel Margin="2">
    
                                                <Image Source="{Binding Img}" Width="96" Height="96"/>
                                                <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/>
                                    
                                           
                                        </StackPanel>
                                        </Border>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>
                            <Label Content="您选择的是:" FontSize="16" ></Label>
                            <Label Content="{Binding Path=SelResult,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="16" />
                        </StackPanel>
                    </StackPanel>
                </GroupBox>
            </StackPanel>
    
        </StackPanel>
    </Window>
    复制代码
    复制代码
    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.CommandWpf;
    using MvvmLightDemo1.Model;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Windows.Input;
    
    namespace MvvmLightDemo1.ViewModel
    {
        public class MainViewModel : ViewModelBase
        {
            private WelcomeModel welcomeModel;
            public WelcomeModel WelcomeModel
            {
                get { return welcomeModel; }
                set { welcomeModel = value; RaisePropertyChanged(() => WelcomeModel); }
            }
    
            private string objParameter = "";
    
            public string ObjParameter
            {
                get { return objParameter; }
                set
                {
                    objParameter = value;
                    RaisePropertyChanged();
                }
            }
    
    
            private int selectIndex = -1;
    
            public int SelectIndex
            {
                get { return selectIndex; }
                set
                {
                    selectIndex = value;
                    RaisePropertyChanged();
                }
            }
            private string selResult = "";
    
            public string SelResult
            {
                get { return selResult; }
                set
                {
                    selResult = value;
                    RaisePropertyChanged();
                }
            }
            private IEnumerable listBoxData = new ObservableCollection<DataModel>()
            {
                  new DataModel(){ Img="/MvvmLightDemo1;component/Img/1.png",Info=" Honey Peach " },
                  new DataModel(){ Img="/MvvmLightDemo1;component/Img/2.png",Info="Tomato" },
                  new DataModel(){ Img="/MvvmLightDemo1;component/Img/3.png",Info="Banana" },
                  new DataModel(){ Img="/MvvmLightDemo1;component/Img/4.png",Info="Chilli " },
                  new DataModel(){ Img="/MvvmLightDemo1;component/Img/5.png",Info="Apple" },
            };
            /// <summary>
            /// LisBox数据模板
            /// </summary>
            public IEnumerable ListBoxData
            {
                get { return listBoxData; }
                set { listBoxData = value; RaisePropertyChanged(() => ListBoxData); }
            }
            /// <summary>
            /// Initializes a new instance of the MainViewModel class.
            /// </summary>
            public MainViewModel()
            {
                WelcomeModel = new WelcomeModel() { WelcomeMsg = "Welcome to MVVMLight World!" };
            }
    
            private string userList = "Mary";
    
            public string UserList
            {
                get { return userList; }
                set
                {
                    userList = value;
                    RaisePropertyChanged();
                }
            }
            private string user = "";
    
            public string User
            {
                get { return user; }
                set { user = value; }
            }
            private bool isCanAddUser = true;
    
            public bool IsCanAddUser
            {
                get { return isCanAddUser; }
                set { isCanAddUser = value; }
            }
    
            #region Command
            private RelayCommand<string> addUserCommand;
    
            public RelayCommand<string> AddUserCommand
            {
                get
                {
                    if (addUserCommand == null)
                    {
                        addUserCommand = new RelayCommand<string>(AddUser, (string p) => { return IsCanAddUser; });
                    }
                    return addUserCommand;
                }
                set { addUserCommand = value; }
            }
            private void AddUser(string par)
            {
                UserList = UserList + "  " + par;
            }
    
    
    
            private RelayCommand<UserModel> addUserCommandWithObjPar;
    
            public RelayCommand<UserModel> AddUserCommandWithObjPar
            {
                get
                {
                    if (addUserCommandWithObjPar == null)
                    {
                        addUserCommandWithObjPar = new RelayCommand<UserModel>(AddUserWithObjPar);
                    }
                    return addUserCommandWithObjPar;
                }
                set { addUserCommandWithObjPar = value; }
            }
            private void AddUserWithObjPar(UserModel par)
            {
                ObjParameter = "UserName: "+ par.UserName + " Password: " + par.PassWord;
            }
    
    
    
            private RelayCommand selectionChangedCommand;
    
            public RelayCommand SelectionChangedCommand
            {
                get
                {
                    if (selectionChangedCommand == null)
                    {
                        selectionChangedCommand = new RelayCommand(SelectChange);
                    }
                    return selectionChangedCommand;
                }
                set { selectionChangedCommand = value; }
            }
            private void SelectChange()
            {
                int i = 0;
                foreach(var a in ListBoxData)
                {
                    if(i == SelectIndex)
                    {
                        SelResult = (a as DataModel).Info;
                        break;
                    }
                    i++;
                }
            }
            #endregion
    
        }
    }
    复制代码
    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MvvmLightDemo1.Model
    {
        public class DataModel
        {
            private string  img;
    
            public string  Img
            {
                get { return img; }
                set { img = value; }
            }
    
            private string info;
    
            public string Info
            {
                get { return info; }
                set { info = value; }
            }
        }
    }
    复制代码

    运行结果如下:

    五、带原事件参数的命令绑定

    代码片段如下:

    复制代码
     <StackPanel>
                <GroupBox Header="带事件参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">
    
                    <StackPanel Orientation="Horizontal">
                        <Button Content="拖拽上传文件" AllowDrop="True">
                            <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Drop">
                                <mvvm:EventToCommand PassEventArgsToCommand="True" Command="{Binding DropCommand}" />
                            </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </Button>
                        <Label Content="FilePath:"  FontSize="16" ></Label>
                        <Label Content="{Binding DraggedFilePath}"  FontSize="16" ></Label>
    
                    </StackPanel>
    
                </GroupBox>
            </StackPanel>
    复制代码
    复制代码
      private RelayCommand<DragEventArgs> dropCommand;
            /// <summary>
            /// 传递原事件参数
            /// </summary>
            public RelayCommand<DragEventArgs> DropCommand
            {
                get
                {
                    if (dropCommand == null)
                        dropCommand = new RelayCommand<DragEventArgs>(e => ExecuteDrop(e));
                    return dropCommand;
                }
                set { dropCommand = value; }
            }
    
            private void ExecuteDrop(DragEventArgs e)
            {
                DraggedFilePath = ((System.Array)e.Data.GetData(System.Windows.DataFormats.FileDrop)).GetValue(0).ToString();
            }
    复制代码
  • 相关阅读:
    select2使用
    Jquery DataTables相关示例
    基于Cef内核的多店铺登录器(含源码)
    Navi.Soft31.产品.登录器(永久免费)
    基于JQuery EasyUI的WebMVC控件封装(含源码)
    EntityFrameWork实现部分字段获取和修改(含源码)
    基于Ado.Net的日志组件
    C#实现七牛云存储
    局域网内手机播放视频
    基于微软企业库的AOP组件(含源码)
  • 原文地址:https://www.cnblogs.com/lzjsky/p/15682796.html
Copyright © 2020-2023  润新知