基本的 MVVM 和 ICommand 使用示例
在 WPF 中设置基本的 MVVM 和 ICommand 用法,以允许从视图对 ViewModel 执行操作。
引言
在此技巧中,我们将学习 WPF 命令。 命令与 MVVM 模式(模型-视图-ViewModel)非常契合。 我们还将了解视图实际上如何了解其 ViewModel
,以及视图如何通过使用 WPF 中的命令来调用 ViewModel
上的操作。
背景
我们将逐步进行,而不是一次查看完整的代码,这将有助于我们更好地理解每部分代码的作用。
让我们看一下 MVVM 架构。
我们使用标准约定来命名类,如下所示
View
的后缀是View
,位于View
的名称之后(例如:StudentListView
)ViewModel
的后缀是ViewModel
,位于ViewModel
的名称之后。 (例如:StudentListViewModel
)Model
的后缀是Model
,位于Model
的名称之后(例如:StudentModel
)。
Using the Code
理论讲够了,现在让我们深入代码,看看 MVVM 的工作示例以及如何在 MVVM 中使用命令。
在 Visual Studio 中创建一个新的 WPF 项目。 将 MainWindow
重命名为 MainWindowView
以遵循我们的约定。
接下来,我们需要创建一个名为 MainWindowViewModel
的新类,它将充当 MainWindowView
的 ViewModel
。
我们在 MVVM 中所做的是告诉 View
它的 ViewModel
是什么。 这可以通过为该视图设置数据上下文来完成。 Model
在 ViewModel
中使用,并且它们在某些特定视图之间没有任何连接。
设置 Datacontext
的示例代码如下所示。
打开 *MainWindowView.xaml.cs* 并设置数据上下文,如下所示。
MainWindowView.xaml.cs
<Window x:Class="WpfExample.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfExample">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
</Grid>
</Window>
这里的 local
是我们命名空间 WpfExample
的别名。 这是必需的,以便框架知道 MainWindowViewModel
在哪里可用。
现在我们已经设置了 MVVM 模式。 现在 MainWindowView
知道它的 ViewModel
是 MainWindowViewModel
。
我们将通过使用简单的绑定来验证这一点。
让我们向视图添加一个按钮,并使用 ViewModel
中的实例设置按钮内容。
View
我们将向视图添加按钮,并将使用绑定设置其内容,如下所示
MainWindowView.xaml.cs
<Window x:Class=" WpfMvvmExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:WpfMvvmExample"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Button Width="100"
Height="100" Content="{Binding ButtonContent}"/>
</Grid>
</Window>
ViewModel
namespace WpfExample
{
class MainWindowViewModel
{
public string ButtonContent
{
get
{
return "Click Me";
}
}
}
}
在上面的代码中,我们告诉 View
从 ViewModel
中存在的 ButtonContent
属性中获取 button
的内容。
<Button Width="100" Height="100" Content="{Binding ButtonContent}"/>
现在,如果我们运行应用程序,我们可以看到按钮内容设置为 string
“Click Me
”。
因此,这表明我们的 MVVM 正常工作。
现在我们进入 ICommand 接口
现在,让我们尝试使用 WPF 中的命令向按钮添加单击功能。
命令提供了一种机制,供视图在 MVVM 架构中更新模型。
首先,我们看一下 ICommand
接口。
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;
我们将创建一个示例应用程序,当单击按钮时,该应用程序会显示一条消息框,其中包含消息“HI
”,并且我们将添加另一个按钮,用于切换是否可以单击 Hi
按钮。
我们创建一个名为 RelayCommand
的类,该类实现 ICommand
接口。 此类充当 ICommand
的增强功能,并将样板代码提取到一个单独的类中。
public class RelayCommand : ICommand
{
private Action<object> execute;
private Predicate<object> canExecute;
private event EventHandler CanExecuteChangedInternal;
public RelayCommand(Action<object> execute)
: this(execute, DefaultCanExecute)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
if (canExecute == null)
{
throw new ArgumentNullException("canExecute");
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
this.CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
this.CanExecuteChangedInternal -= value;
}
}
public bool CanExecute(object parameter)
{
return this.canExecute != null && this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void OnCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChangedInternal;
if (handler != null)
{
//DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
handler.Invoke(this, EventArgs.Empty);
}
}
public void Destroy()
{
this.canExecute = _ => false;
this.execute = _ => { return; };
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
CommandManager.RequerySuggested
负责启用和禁用“Click to Hii
”按钮。
视图
<Window x:Class="WpfExample.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfExample">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Command="{Binding HiButtonCommand}"
CommandParameter="Hai" Content="{Binding HiButtonContent}"
Width="100"
Height="100" />
<Button Grid.Row="1" Content="Toggle Can Click"
Command="{Binding ToggleExecuteCommand}" Width="100" Height="100"/>
</Grid>
</Window>
ViewModel
class MainWindowViewModel
{
private ICommand hiButtonCommand;
private ICommand toggleExecuteCommand { get; set; }
private bool canExecute = true;
public string HiButtonContent
{
get
{
return "click to hi";
}
}
public bool CanExecute
{
get
{
return this.canExecute;
}
set
{
if (this.canExecute == value)
{
return;
}
this.canExecute = value;
}
}
public ICommand ToggleExecuteCommand
{
get
{
return toggleExecuteCommand;
}
set
{
toggleExecuteCommand = value;
}
}
public ICommand HiButtonCommand
{
get
{
return hiButtonCommand;
}
set
{
hiButtonCommand = value;
}
}
public MainWindowViewModel()
{
HiButtonCommand = new RelayCommand(ShowMessage, param => this.canExecute);
toggleExecuteCommand = new RelayCommand(ChangeCanExecute);
}
public void ShowMessage(object obj)
{
MessageBox.Show(obj.ToString());
}
public void ChangeCanExecute(object obj)
{
canExecute = !canExecute;
}
}
最终应用程序看起来像这样
我已将示例项目随此技巧一起附加。 希望您觉得这个技巧有用。