【问题标题】:Commanding in MVVM (WPF)--how to return a value?MVVM (WPF) 中的命令——如何返回一个值?
【发布时间】:2010-02-10 20:18:42
【问题描述】:

我使用 MVVM 模式已经有一段时间了,但在现实生活中我仍然会遇到问题。这是另一个: 我使用命令并在 ViewModel 中处理要处理的事件。到目前为止,一切都很好。但我使用 MVVM 的项目实际上是一个类库。运行命令代码后,我需要能够将对象发送回调用应用程序。有什么建议的方法来做到这一点?

具体来说: 在我的调用应用程序中,我有一个 XAML 页面直接绑定到库的 ViewModel,其中包含一个对象“Thing1”。单击按钮时,会调用 ViewModel 中的方法(称为“CopyThing1()”)。它复制“Thing1”以创建“Thing2”。然后我需要将“Thing2”发送回调用应用程序。

谢谢!!!

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    命令不会返回值,它们会更改应用程序的状态。如果将 ICommands 附加到 ViewModels,这非常简单,因为您可以通过在执行命令时简单地改变 ViewModel 来做到这一点。

    使用来自Josh Smith's excellent MVVM article 的 RelayCommand:

    public class MyViewModel : INotifyPropertyChanged
    {
        private readonly ICommand mutateCommand;
        private Thing thing;
    
        public MyViewModel()
        {
            this.mutateCommand = new RelayCommand(this.Mutate);
        }
    
        public ICommand MutateCommand
        {
            get { return this.mutateCommand; }
        }
    
        public Thing Thing
        {
            get { return this.thing; }
            set
            {
                this.thing = value;
                // raise PropertyChanged event here...
            }
        }
    
        private void Mutate(object parameter)
        {
            this.Thing = new Thing();
        }
    }
    

    调用myVM.MutateCommand.Execute(new object()); 后,您可以访问myVM.Thing 的新值。

    【讨论】:

    • 谢谢。我曾想过这个。其实我的例子并不是最好的。我真正想做的是让我的 XAML 页面绑定到一个对象 (Thing1),然后单击该页面上的一个按钮并实例化第二个对象 (Thing2--与 Thing1 相同的结构,但不是 Thing1) .所以我可以在我的 ViewModel 中声明一个 Thing1 和一个 Thing2。创建 Thing2 时,绑定页面需要在代码隐藏中响应,即它不仅仅是需要与 UI 相关的响应。不知道如何让代码隐藏来响应这个非 UI 事件。
    • @ml_black:不要使用代码隐藏;使用 ViewModels 并让 Views 简单地反映 ViewModels 的变化。沟通只有一种方式。这是一种更清洁的方法。
    • 我同意。但是调用应用程序没有使用 ViewModels。而这个 ViewModel 意味着不止一个调用应用程序。因此,在这种情况下,来自 Thing2 的信息必须由每个调用应用程序以自己的方式使用。该库将是纯粹的 MVVM。
    【解决方案2】:

    如果 Thing2 是您的视图模型上的另一个属性,您可以使用普通的 INotifyPropertyChanged 来通知 UI 更改。

    您还可以使用PrismEventAggregator 来实现更解耦的方法

    【讨论】:

    • 谢谢。这是我最初的想法,但调用应用程序中的响应将不仅仅是 UI 响应。所以我不确定如何让 Thing2 创建启动调用应用程序的代码隐藏可以响应的事件。
    • 其实你知道使用EventAggregator的好例子吗?另外,与开箱即用相比,Prism 版本的优势是什么?
    • 好的,我现在明白了。不知道 Prism 是从哪里来的。快速入门是您所知道的最简单的示例吗?
    • 是的,快速入门与 Prism 一样简单。尽管 Prism 被一些人批评为过于笨拙。其他几个 MVVM 框架(参见 stackoverflow.com/questions/1280462)也有这种模式的实现。
    【解决方案3】:

    理想的方法是定义一个继承自 ICommand 的新类,如下所示:

    public abstract class Command2<T1, T2> : ICommand {
        public abstract T2 Execute2(T1 parameter);
    }
    
    public class DelegateCommand2<T1, T2> : Command2<T1, T2> {
        public DelegateCommand2(Func<T1, T2> execute, Predicate<T1> canExecute) {
            _execute = execute;
            _canExecute = canExecute;
        }
    
        public override T2 Execute2(T1 parameter) {
            if (CanExecute(parameter) == false)
                return default(T2);
            else
                return _execute((T1)parameter);
        }
    }
    

    请注意,Execute2 像普通函数一样返回值。 这是它的使用方法。

        private readonly ICommand _commandExample = new DelegateCommand2<int, Point3D>(
            commandExample_Executed,
            commandExample_CanExecute
        );
    
        public Command2<int, Point_3D> CommandExample {
            get {
                return (Command2<int, Point_3D>) _commandExample;
            }
        }
    
        private static Point3D commandExample_Executed(int index) {
            return Fun1(index); //Fun1 returns a Point_3D
        }
    
        private static bool commandExample_CanExecute(int index) {
            return true;
        }
    

    调用 Execute2 而不是 Execute 将返回值。

    【讨论】:

      【解决方案4】:

      虽然关于命令的信息清晰正确,但它不能应用于我的情况,因为需要发生的响应是在调用应用程序中而不使用 MVVM 并且它不仅仅是 UI 响应。我确实调查了 Prism,但发现它对于我目前需要的东西来说太复杂了。我最终提出并处理了事件,如此处所述--> WPF MVVM Correct Way to Fire Event on View From ViewModel

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-28
        • 2013-01-22
        • 1970-01-01
        • 1970-01-01
        • 2020-03-02
        • 1970-01-01
        相关资源
        最近更新 更多