【问题标题】:When implementing ICommand in MVVM I'm missing something在 MVVM 中实现 ICommand 时,我遗漏了一些东西
【发布时间】:2013-04-16 17:19:48
【问题描述】:

我对 C# 和 WPF 非常陌生,我来自 LAMP Web 应用程序背景。我已经尝试过一些关于这个主题的教程,但它们让我很难过。

https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/ http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

在第一个教程中,应用程序以一个简单的界面打开。一个文本框和两个按钮。当您更新 ProductId 文本框时,从 0 变为 1,“获取产品”按钮变为活动状态。当您单击“获取产品”按钮时,会出现 DataTemplate 的内容。我看不到这些事情实际发生在哪里。是什么导致按钮变为活动状态?是什么导致表单出现?

希望你们能帮我把它变笨=)

【问题讨论】:

  • 它有点长(而且我知道我有偏见),但如果您还不熟悉 WPF,我认为我的 MVVM 系列更容易理解。 reedcopsey.com/series/windows-forms-to-mvvm我有一整篇文章介绍了那里的指挥,以比您正在阅读的更基本的方式。
  • 再次感谢 Reed,我一定会去看看的!

标签: c# wpf mvvm icommand relaycommand


【解决方案1】:

这些按钮被激活或停用,因为它们绑定到 ICommandICommand 包含一个CanExecute 属性,用于确定按钮是否处于活动状态。

我看不出这些事情实际发生在哪里。

该命令使用委托:

 _getProductCommand = new RelayCommand(
                param => GetProduct(),
                param => ProductId > 0
            );

ProductId > 0(代理返回真)时,第二个委托会导致激活命令(CanExecute 变为真)。

当您单击按钮时,命令的Execute 方法将触发并执行操作。

至于首先启动的窗口,请查看标题为“启动示例”的部分 - app.xaml.cs 中有代码,用于首先显示窗口。

【讨论】:

  • 非常感谢里德。花了一点时间,但终于能够理解发生了什么。我最初期望某种方法可以真正打开按钮,而不是它的活动状态是 Predicate(第二个 lambda 参数,对于那些像我一样困惑的人)为真的结果。
  • @lose_the_grimm 谓词是一种方法 - 只要CanExecuteChanged 触发,或者 WPF 决定检查它,它就会运行。
  • 我的说法不准确吗?
  • @lose_the_grimm 不——它是准确的——你提到你“期望某种方法来实际打开按钮”——谓词是一种这样做的方法,但它是间接的。
  • 也许这表明我还没有完全理解它。在这种情况下,是什么决定了绑定到按钮的命令是由单击触发的,而不是双击触发的。甚至悬停或聚焦?
【解决方案2】:

在那个具体的例子中你可以看到:

<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding ProductId}" />

TextBox 使用data binding 将其Text 属性绑定到当前数据上下文(这是视图模型的一个实例)上的ProductId

当您在TextBox 中键入文本时,其值将在视图模型的ProductId 属性上自动更新。

该命令检查ProductId 的值是否大于0 以确定Button 是否启用。

可以看到Button的命令设置为GetProductCommand

<Button ... Command="{Binding Path=GetProductCommand}" ... />

GetProductCommand 使用表达式 ProductId &gt; 0 作为其 CanExecute 谓词:

_getProductCommand = new RelayCommand(
              param => GetProduct(),
              param => ProductId > 0
);

WPF 将执行此 lambda 表达式 ProductId &gt; 0,其结果将确定是否启用了 Button。启用并单击按钮后,将执行第一个 lambda 表达式 - GetProduct()

说了这么多,you really should be using an MVVM framework,这些框架还有其他机制可以在您的视图模型上调用方法,从而克服了命令的一些限制。

【讨论】:

  • 我盯着代码看了一会儿,慢慢地,慢慢地,我开始摸索到底发生了什么。我还有一个问题。如果我想双击我的按钮怎么办?或者这是一个框架会比我包含的教程示例更容易解决的问题?
  • 好吧,像 Caliburn.Micro (caliburnmicro.codeplex.com) 这样的东西提供了“Actions”,它可以让您非常轻松地从 Button 的 MouseDoubleClick 事件调用视图模型上的方法。跨度>
【解决方案3】:

本质上,MVVM 或 Model、View、ViewModel 背后的理念是删除背后的代码并分离出应用程序的各个层,以便它们可以独立工作。您的 GUI 或视图与 Viewmodel 或代码隐藏之间的交互并没有像您想象的那样发生。很多人对视图模型实际上如何与 gui 或视图交互感到困惑。我是一名 winforms 开发人员,拥有代码隐藏文件,您可以在其中轻松查看隐藏代码中的事件处理程序并在逻辑上遵循代码。在您将 XAML gui 的数据上下文设置为视图模型的 MainWindow 代码中,如下所示。

public partial class MainWindow : Window
{
    #region Members
    SongViewModel _viewModel;
    int _count = 0;
    #endregion

    public MainWindow()
    {
        InitializeComponent();

        //  We have declared the view model instance declaratively in the xaml.
        //  Get the reference to it here, so we can use it in the button click event.
        _viewModel = (SongViewModel)base.DataContext;
    }

    private void ButtonUpdateArtist_Click(object sender, RoutedEventArgs e)
    {
        ++_count;
        _viewModel.ArtistName = string.Format("Elvis ({0})", _count);
    }
}    

然后 {Binding Path=Property} 将您的 _viewModel 属性连接到 XAML 元素。添加 RaisePropertyChanged 是为了通知 gui 该属性的值已更改。

public string ArtistName
    {
        get { return Song.ArtistName; }
        set
        {
            if (Song.ArtistName != value)
            {
                Song.ArtistName = value;
                RaisePropertyChanged("ArtistName");
            }
        }
    }

View 模型的 ArtistName 属性绑定到标签,就像在 XAML 中一样

这或多或少是您在 gui 和代码之间的交流。因此,例如在您的第一个示例中,当您将文本框从 0 更改为 1 时,它将更新您的 ViewModel 中的 ProductID 属性。您可以在您的 ICommand GetProductCommand 中看到有一个参数被传递给 relayCommand 用于 ProductID > 0。现在它的 1 canexecute 为真,因此该命令现在可以执行并且按钮变为可点击。当您单击它时,GetProduct 是发生的操作,然后该方法将您的 CurrentProduct 属性设置为值。产品信息的 Datatemplate 绑定到 xaml 中的 ProductModel,ProductModel 绑定到 CurrentProduct,因此现在在该数据模板中 CurrentProduct 的属性可以绑定到 xaml 元素,因此 CurrentProduct.ProductName 或绑定到

<TextBox Grid.Row="1" Grid.Column="1"  Text="{Binding ProductName}" />

一开始会让人困惑,但是当你掌握了它的窍门后,它就会完全有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-12
    • 2011-05-14
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 2021-04-25
    • 1970-01-01
    相关资源
    最近更新 更多