65.9K
CodeProject 正在变化。 阅读更多。
Home

基本的 MVVM 和 ICommand 使用示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (55投票s)

2014 年 8 月 31 日

CPOL

3分钟阅读

viewsIcon

362645

downloadIcon

55

在 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 的新类,它将充当 MainWindowViewViewModel

我们在 MVVM 中所做的是告诉 View 它的 ViewModel 是什么。 这可以通过为该视图设置数据上下文来完成。 ModelViewModel 中使用,并且它们在某些特定视图之间没有任何连接。

设置 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 知道它的 ViewModelMainWindowViewModel

我们将通过使用简单的绑定来验证这一点。

让我们向视图添加一个按钮,并使用 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";
            }
        }
    }
}

在上面的代码中,我们告诉 ViewViewModel 中存在的 ButtonContent 属性中获取 button 的内容。

<Button Width="100" Height="100" Content="{Binding ButtonContent}"/>

现在,如果我们运行应用程序,我们可以看到按钮内容设置为 stringClick 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;
        }
    }

最终应用程序看起来像这样

我已将示例项目随此技巧一起附加。 希望您觉得这个技巧有用。

© . All rights reserved.