ICommand 不起作用
ICommand doesn't work
我从 MVVM
模式开始,我的按钮命令有问题。我有一个 window,其中包含一个用于登录的 TextBox
和一个带有密码 DependencyProperty
的自定义 PasswordBox
作为密码(我知道任何密码都不应该保存在内存中,但是它只是为了好玩,所以不要沮丧 :) ) 。还有一个按钮,我希望当且仅当登录名和密码都不为空时才启用它。但是我的命令不能正常工作。这是代码:
登录窗口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>
我的 LoginViewModel class
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() { }
}
另外 MyPasswordBox
class 可能有用:
<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;
}
}
我为检查 SaveUserCommand CanExecute 方法的结果编写了一些单元测试,它们都通过了。此外,我 运行 Visual Studio 中的调试在 Login
和 Password
属性的设置器中添加断点,它们都设置正确。
我 运行 不知道我会做错什么。有人可以帮助我吗?
我觉得我没有正确通知有关更改的命令,但我不知道该怎么做
为了让 WPF 获取命令是否可以执行的更改,需要触发命令的 CanExecuteChanged
事件。
您需要在登录名或密码更改时触发此事件。您没有显示 class Command
的来源,但它需要有一个方法来触发其 CanExecuteChanged
事件。然后,只需从 Login
和 Password
属性 设置器中调用此方法。
我从 MVVM
模式开始,我的按钮命令有问题。我有一个 window,其中包含一个用于登录的 TextBox
和一个带有密码 DependencyProperty
的自定义 PasswordBox
作为密码(我知道任何密码都不应该保存在内存中,但是它只是为了好玩,所以不要沮丧 :) ) 。还有一个按钮,我希望当且仅当登录名和密码都不为空时才启用它。但是我的命令不能正常工作。这是代码:
登录窗口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>
我的 LoginViewModel class
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() { }
}
另外 MyPasswordBox
class 可能有用:
<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;
}
}
我为检查 SaveUserCommand CanExecute 方法的结果编写了一些单元测试,它们都通过了。此外,我 运行 Visual Studio 中的调试在 Login
和 Password
属性的设置器中添加断点,它们都设置正确。
我 运行 不知道我会做错什么。有人可以帮助我吗?
我觉得我没有正确通知有关更改的命令,但我不知道该怎么做
为了让 WPF 获取命令是否可以执行的更改,需要触发命令的 CanExecuteChanged
事件。
您需要在登录名或密码更改时触发此事件。您没有显示 class Command
的来源,但它需要有一个方法来触发其 CanExecuteChanged
事件。然后,只需从 Login
和 Password
属性 设置器中调用此方法。