如何避免 ViewModel 中的命令混乱?

Posted

技术标签:

【中文标题】如何避免 ViewModel 中的命令混乱?【英文标题】:How can I avoid command clutter in the ViewModel? 【发布时间】:2012-01-23 01:34:54 【问题描述】:

我正在构建一个使用很多命令的应用程序,它们使我的视图模型变得混乱。 MVVM 对我来说是新的,如果这个问题有点愚蠢,很抱歉。有没有办法减少混乱?例如在这里你可以看到杂乱的一部分..

    private void InitializeCommands()
    
        LogoutCommand = new RelayCommand(Logout);
        OpenCommand = new RelayCommand(SetImage);
        SaveCommand = new RelayCommand(SaveImage, SaveImageCanExecute);
        UploadToFlickrCommand = new RelayCommand(UploadToFlickr);
        CropCommand = new RelayCommand(SetCropMouseEvents);
        RemoveRedEyeCommand = new RelayCommand(SetRemoveRedEyeMouseEvents);
        TextInputCropCommand = new RelayCommand(CropFromText);
        ReloadImageCommand = new RelayCommand(ReloadImage);
        FlipYCommand = new RelayCommand(FlipY);
        Rotate90RCommand = new RelayCommand(Rotate90R);
        FlipXCommand = new RelayCommand(FlipX);
        ToGrayscaleCommand = new RelayCommand(ToGrayscale);
        ToSepiaCommand = new RelayCommand(ToSepia);
        WindowClosingCommand = new RelayCommand(WindowClosing);
        EffectsViewCommand = new RelayCommand(() => CurrentToolView = new EffectsView());
        AddTextCommand = new RelayCommand(() => CurrentToolView = new AddTextView());
        ResizeCommand = new RelayCommand(() => CurrentToolView = new ResizeView());
        CropViewCommand = new RelayCommand(() => CurrentToolView = new CropView());
        RedEyeCommand = new RelayCommand(() => CurrentToolView = new RedEyeView());
        RotateViewCommand = new RelayCommand(() => CurrentToolView = new RotateView());
        ExitCommand = new RelayCommand(() => Application.Current.Shutdown());
        FullscreenCommand = new RelayCommand(() =>
                                                 
                                                     var fs = new FullscreenView
                                                                  FullscreenImage = CurrentImage.LoadedImage;
                                                     fs.Show();
                                                 );
        HandleDropCommand = new RelayCommand<DragEventArgs>(e => OnFileDrop(this, e));
        Messenger.Default.Register<User>(this, "UserLogin", SetUser);
        Messenger.Default.Register<FlickrAccount>(this, "AddedAccount", AddAccount);
        Messenger.Default.Register<string>(this, "INeedAUser", SendUser);
        Messenger.Default.Register<string>(this, "INeedAImage", SendImage);
    

【问题讨论】:

我也有兴趣看到一个好的答案,但 AFAIK 这是拥有所有松散耦合优点的代价。 【参考方案1】:

所以你有以下命令:

    文件操作(打开、保存、上传到 Flicker)

    窗口操作(全屏、关闭)

    编辑(旋转、调整大小、颜色等)

考虑将相关命令组合(组合)到一个自定义类中,例如 FileCommands。如果适用,请创建多级层次结构。如果您的视图中有分层菜单,您可能需要类似的命令层次结构。

然后,为每个命令组(例如 FileController)创建一个 控制器,并在控制器创建方法中将 FileCommands 组中的命令注册到相关服务。

请参阅http://waf.codeplex.com/ 示例应用程序(例如 BookController.cs),了解有关如何实际实现 Controller/ViewModel 映射的一些想法。但是请注意,这不是完全相同的场景(没有将命令分成组)。

【讨论】:

很有趣,我喜欢这个主意。看起来有点复杂(对于我这个新手来说),但我会看看它,让你知道我是怎么做的!谢谢你的回答:) 如果您还不想使用控制器,那么只需按照建议将相关命令分组并将 InitializeCommands 方法拆分为 InitializeFileCommands、InitializeWindowCommands 等。【参考方案2】:

使用 Caliburn Micro。对于名为 name="Logout" 的按钮,ViewModel 中唯一需要的是一个名为 Logout 的公共方法。

并且没有对流绑定:

<Button Content="Remove"
        cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />

然后在 ViewModel 上添加一个名为 Remove 的方法,并在该示例中将 DataContext 传递给该方法。

【讨论】:

什么是 Caliburn Micro,使用它有多容易?我们目前正在使用 MVVM light ,它们可以一起使用吗?谢谢你的回复:) CM 是 WPF 和 SL 的基于约定的 MvvM 框架。 caliburnmicro.codeplex.com。入门还不错,但我认为您不会同时使用两者。【参考方案3】:

您的 ViewModel 意味着成为 View 和 Model 之间的粘合剂。这意味着,除非您可以通用地迭代模型,否则它将始终包含“胶线”的枚举。

我能想象你可以摆脱的唯一混乱是如果你不需要 XXXCommand 属性;在这种情况下,您可以创建一个类似属性的集合,例如(伪代码)

private void createCommands() 
   var commands=
      "Logout"=>new RelayCommand(Logout),
      "Exit"=>new RelayComand( ()=>Application.Current.Shutdown() ),
     ....
   ;
   foreach( var key,cmd in commands )
      glue(key,cmd);
   
;

除了将它们粘贴到正确的视图活页夹之外,没有其他理由保留对您在此处创建的对象的引用。

但话又说回来,为什么不使用 Property 成语呢?再说一遍:在我看来,杂乱的数量是相当有限的。

【讨论】:

谢谢你的回答,我会再看一遍代码,明天再问老师。我稍后会重新发布代码,您可以看到结果:) 请注意:在字符串中包含名称会使它们对编译器不可见(即它无法检查一致性)。另一方面;它也无法检查是否使用了属性...

以上是关于如何避免 ViewModel 中的命令混乱?的主要内容,如果未能解决你的问题,请参考以下文章

屏幕旋转导致Activity销毁重建,ViewModel是如何恢复数据的

使用 SwiftUI/Combine,如何避免在 ViewModel 中放置可取消项

如何在没有代码隐藏的情况下处理 ViewModel 中的 WPF 路由命令?

MongoDB如何避免SQL注入混乱?

WPF 将 UI 事件绑定到 ViewModel 中的命令

MVVM模式解析和在WPF中的实现