[Prism练习] Prism下MVVM中命令绑定的CanExecute问题

近来练习Prsim下实现MVVM的方式。

找到Command绑定有点问题,想拿出来讨论下。

比如,一个新增资料的界面中,我想:用户必须将所有应填写的数据项填写完毕后提交按钮才可用。

于是我们开始劵起袖子


  •  建立WPF项目,NuGet添加对Prism的引用,创建相关文件夹
  • 建立一个简单的model和service
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace MvvmDemo2.Models
 7 {
 8     public class Person
 9     {
10         public string Name { get; set; }
11         public string Email { get; set; }
12 
13         public bool Validate() 
14         {
15             if (string.IsNullOrEmpty(this.Name) || string.IsNullOrEmpty(this.Email))
16             {
17                 return false;
18             }
19             else 
20             {
21                 return true;
22             }
23         }
24     }
25 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace MvvmDemo2.Models
 7 {
 8     public  class PersonService
 9     {
10         public Person GetPerson() 
11         {
12             return new Person { Name = "坑定", Email = "sdj@163.com" };
13         }
14 
15         public Person CreatePerson() 
16         {
17             return new Person();
18         }
19 
20         public void Save(Person person) 
21         {
22             //TODO....
23         }
24     }
25 }
  • 建立ViewModel
    View Code
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 
     6 using Microsoft.Practices.Prism.Commands;
     7 using Microsoft.Practices.Prism.ViewModel;
     8 
     9 using MvvmDemo2.Models;
    10 
    11 namespace MvvmDemo2.ViewModels
    12 {
    13     public class PersonViewModel:NotificationObject
    14     {
    15         private PersonService svc;
    16 
    17         public PersonViewModel()
    18         {
    19             this.svc = new PersonService();
    20             this.Person = svc.CreatePerson();
    21             this.SaveDataCommand = new DelegateCommand<Person>(SaveData, CanSaveData);
    22         }
    23 
    24         private Person person;
    25         public Person Person 
    26         {
    27             get 
    28             { 
    29                 return person; 
    30             }
    31             set 
    32             { 
    33                 person = value;
    34                 RaisePropertyChanged("Person");
    35             }
    36         }
    37 
    38         public string PersonName 
    39         {
    40             get { return this.Person.Name; }
    41             set 
    42             { 
    43                 this.Person.Name = value;
    44                 RaisePropertyChanged("PersonName");
    45                 //RaiseCanSaveDataChanged();
    46             }
    47         }
    48 
    49         public string PersonEmail 
    50         {
    51             get { return this.Person.Email; } 
    52             set 
    53             {
    54                 this.Person.Email = value;
    55                 RaisePropertyChanged("PersonEmail");
    56                 //RaiseCanSaveDataChanged();
    57             }
    58         }
    59 
    60         public DelegateCommand<Person> SaveDataCommand { get; set; }
    61 
    62         public void SaveData(Person person) 
    63         {
    64             this.svc.Save(person);
    65         }
    66 
    67         public bool CanSaveData(Person person) 
    68         {
    69             if (person == null)
    70             {
    71                 return false;
    72             }
    73             else 
    74             {
    75                 bool isValid = person.Validate();
    76                 return isValid;
    77             }
    78         }
    79 
    80         private void RaiseCanSaveDataChanged()
    81         {
    82             //DelegateCommand<Person> cmd = this.SaveDataCommand as DelegateCommand<Person>;
    83             //cmd.RaiseCanExecuteChanged();
    84             this.SaveDataCommand.RaiseCanExecuteChanged();
    85            
    86         }
    87 
    88         
    89     }
    90 }

    里面有SaveDataCommand用于模拟保存命令,我希望用户必须输入了Person.Name Person.Email命令才能够被执行

  • 建立View
    View Code
     1 <Window x:Class="MvvmDemo2.Views.PersonViewModel"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         xmlns:vm="clr-namespace:MvvmDemo2.ViewModels"
     5         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
     6         xmlns:ie="http://schemas.microsoft.com/expression/2010/interactions"
     7         xmlns:cmd="clr-namespace:Microsoft.Practices.Prism.Commands;assembly=Microsoft.Practices.Prism"
     8         Title="PersonViewModel" Height="300" Width="300">
     9     <Window.DataContext>
    10         <vm:PersonViewModel></vm:PersonViewModel>
    11     </Window.DataContext>
    12     <Window.Resources>
    13         <Style x:Key="TextBlockStyle" TargetType="TextBlock">
    14             <Setter Property="Padding" Value="5"></Setter>
    15             <Setter Property="Background" Value="AliceBlue"></Setter>
    16             <Setter Property="Foreground" Value="Blue"></Setter>
    17         </Style>
    18         <Style  TargetType="StackPanel">
    19             <Setter Property="Background" Value="#FFFFF0"></Setter>
    20         </Style>
    21         <Style x:Key="TextBoxStyle" TargetType="TextBox">
    22             <Setter Property="Margin" Value="5"></Setter>
    23             <Setter Property="Background" Value="WhiteSmoke"></Setter>
    24             <Setter Property="Foreground" Value="Black"></Setter>
    25             <Setter Property="BorderBrush" Value="Blue"></Setter>
    26         </Style>
    27     </Window.Resources>
    28     <StackPanel>
    29         <TextBlock Text="姓名:" Style="{StaticResource TextBlockStyle}" ></TextBlock>
    30         <TextBox  Style="{StaticResource TextBoxStyle}" Text="{Binding PersonName}"></TextBox>
    31         <TextBlock Text="Email:" Style="{StaticResource TextBlockStyle}"></TextBlock>
    32         <TextBox  Style="{StaticResource TextBoxStyle}"  Text="{Binding PersonEmail}"></TextBox>
    33         
    34         <Button Content="添加B" Margin="5" IsEnabled="{Binding CanSaveData}">
    35             <i:Interaction.Triggers>
    36                     <i:EventTrigger EventName="Click">
    37                         <i:InvokeCommandAction Command="{Binding SaveDataCommand}" CommandParameter="{Binding Person}"></i:InvokeCommandAction>
    38                 </i:EventTrigger>
    39             </i:Interaction.Triggers>
    40         </Button>
    41 
    42         <Button  Content="添加A" Margin="5" 
    43                     cmd:Click.Command="{Binding SaveDataCommand}"
    44                     cmd:Click.CommandParameter="{Binding Person}"></Button>
    45 
    46         <Button Content="添加C" Margin="5" Command="{Binding SaveDataCommand}" CommandParameter="{Binding Person}"/>
    47 
    48     </StackPanel>
    49 </Window>

    我翻查了资料Prism下实现命令绑定主要有如下几种方式

            <!-- 借助Blend -->
            <Button Content="添加B" Margin="5" IsEnabled="{Binding CanSaveData}">
                <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <i:InvokeCommandAction Command="{Binding SaveDataCommand}" CommandParameter="{Binding Person}"></i:InvokeCommandAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <!--Prism 命令-->
            <Button  Content="添加A" Margin="5" 
                        cmd:Click.Command="{Binding SaveDataCommand}"
                        cmd:Click.CommandParameter="{Binding Person}"></Button>
            <!--普通命令-->
            <Button Content="添加C" Margin="5" Command="{Binding SaveDataCommand}" CommandParameter="{Binding Person}"/>
  •  看看运行效果



    可见不管是否输入了系统要求完整信息提几种交按钮的状态都没有起变化;

  • 很疑惑,带着问题去找解答发现在Stack Overflow有人提出类似的问题

  • 回来修改了下代码 ViewModel代码
            public string PersonName 
            {
                get { return this.Person.Name; }
                set 
                { 
                    this.Person.Name = value;
                    RaisePropertyChanged("PersonName");
                    RaiseCanSaveDataChanged();
                }
            }
    
            public string PersonEmail 
            {
                get { return this.Person.Email; } 
                set 
                {
                    this.Person.Email = value;
                    RaisePropertyChanged("PersonEmail");
                    RaiseCanSaveDataChanged();
                }
            }
            private void RaiseCanSaveDataChanged()
            {
                //DelegateCommand<Person> cmd = this.SaveDataCommand as DelegateCommand<Person>;
                //cmd.RaiseCanExecuteChanged();
                this.SaveDataCommand.RaiseCanExecuteChanged();
               
            }

    这下按钮 A、C 有了效果

    按钮B仍然没有效果,B后台逻辑是是OK的,只是显示状态有问题,是不是Blend,Prism两家有些恩怨.... -.-!
    鉴于前面的添加了一些代码有些不爽的感觉,于是我想B方式可变通,而且B方式实际更灵活。

  • 有知道的帮我解答下,谢谢

 附件

原文地址:https://www.cnblogs.com/bikaqiou2000/p/3062047.html