简体   繁体   English

ICommand不起作用

[英]ICommand doesn't work

I am starting with MVVM pattern and I have a problem with my button's command. 我从MVVM模式开始,我的按钮命令有问题。 I have a window which contains a TextBox for login and a custom PasswordBox with Password DependencyProperty for password (I know that any password should not be kept in memory, however it is only for fun, so do not be frustrated :) ) . 我有一个窗口,其中包含用于登录的TextBox和具有用于密码的Password DependencyProperty的自定义PasswordBox (我知道不应将任何密码保留在内存中,但是,这只是出于娱乐目的,所以不要感到沮丧:))。 There is also a button and I want it to be enabled if and only if the login and password are both not empty. 还有一个按钮,当且仅当登录名和密码都不为空时,我才希望启用它。 However my command does not work properly. 但是我的命令无法正常工作。 Here is the code: 这是代码:

LoginWindow xaml: LoginWindow xaml:

<Window x:Class="WpfMVVMApplication1.LoginWindow"
    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:WpfMVVMApplication1"
    xmlns:vm="clr-namespace:WpfMVVMApplication1.ViewModel"
    mc:Ignorable="d"
    Title="Login" WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
    Width="250" Height="150">
<Window.DataContext>
    <vm:LoginViewModel />
</Window.DataContext>
<Window.Resources>
    <!-- here some styles for controls -->
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="1.5*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Text="Login:"/>
    <TextBlock Text="Password:" Grid.Row="1"/>
    <TextBox Text="{Binding Login, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
    <local:MyPasswordBox Grid.Row="1" PasswordText="{Binding Password, Mode=TwoWay}"/>
    <Button Command="{Binding SaveUserCommand}"/>
</Grid>

My LoginViewModel class 我的LoginViewModel类

public class LoginViewModel : INotifyPropertyChanged
{
    public LoginViewModel()
    {
        SaveUserCommand = new Command(x => SaveUser(), x => { return !string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password); });
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public ICommand SaveUserCommand { get; private set; }

    private string login;
    private string password;
    public string Login
    {
        get
        {
            return login;
        }
        set
        {
            login = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Login"));
        }
    }

    public string Password
    {
        get
        {
            return password;
        }
        set
        {
            password = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Password"));
        }
    }

    public void SaveUser() { }
}

Also MyPasswordBox class may be useful: MyPasswordBox类也可能有用:

<UserControl x:Class="WpfMVVMApplication1.MyPasswordBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfMVVMApplication1"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <PasswordBox x:Name="password" PasswordChanged="password_PasswordChanged"/>
</Grid>

public partial class MyPasswordBox : UserControl
{
    public MyPasswordBox()
    {
        InitializeComponent();
        PasswordText = "";
    }

    public static readonly DependencyProperty PasswordTextProperty =
        DependencyProperty.Register("PasswordText", typeof(string), typeof(MyPasswordBox), new FrameworkPropertyMetadata(""));

    public string PasswordText
    {
        get { return (string)GetValue(PasswordTextProperty); }
        set { SetValue(PasswordTextProperty, value); }
    }

    private void password_PasswordChanged(object sender, RoutedEventArgs e)
    {
        PasswordText = password.Password;
    }
}

I wrote some unit tests for that which checks the result of SaveUserCommand CanExecute method and they all passed. 我编写了一些单元测试,以检查SaveUserCommand CanExecute方法的结果,并通过了所有测试。 Furthermore, I run the debug in Visual Studio adding breakpoints in setters of Login and Password properties and they both are set properly. 此外,我在Visual Studio中运行调试,在“ Login和“ Password属性的设置器中添加断点,并且它们均已正确设置。

I have run out of ideas what I could make wrong. 我没办法弄清楚我可能会做错什么。 Can anybody help me? 有谁能够帮助我?

I feel that I don't notify the command about the changes properly, however I do not know how to do that 我觉得我没有适当地通知有关更改的命令,但是我不知道该怎么做

In order for WPF to pick up a change to whether a command can be executed, the command's CanExecuteChanged event needs to be fired. 为了使WPF能够更改是否可以执行命令,需要触发命令的CanExecuteChanged事件。

You will need to fire this event when the login or the password changes. 登录名或密码更改时,您将需要触发此事件。 You haven't shown the source of your class Command , but it will need to have a method that fires its CanExecuteChanged event. 您尚未显示Command类的源,但是它将需要一个触发其CanExecuteChanged事件的方法。 Then, just call this method from the Login and Password property setters. 然后,只需从“ Login和“ Password属性设置器中调用此方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM