为了账号安全,请及时绑定邮箱和手机立即绑定

MVVM 事件处理程序从何而来

MVVM 事件处理程序从何而来

C#
繁华开满天机 2021-10-09 10:03:23
我正在编写一个简单的 MVVM 应用程序来研究正确的代码设计。完成它需要一段时间,但事情进展顺利。我有一个关于如何处理事件的问题,以及代码应该放在 ViewModel 中还是代码隐藏中。首先,绑定事件有两种技术,一种是使用 Blend Interactivity DLL 绑定到命令,另一种是使用MethodBindingExtension类。使用交互 DLL,它允许使用 EventArgs 转换器将事件参数转换为只包含我们需要的数据的 UI 不可知类型。我不认为 MethodBindingExtension 这样做,但它更灵活。但是,当您需要设置事件 args 值时,这个事件 args 转换器将无济于事?(或者它可能允许将值转换回来,还没有检查这些类)我喜欢使用 MethodBindingExtension,现在我的 ViewModel 中有这段代码。我不喜欢它的是我使用了特定的 UI 类型,这现在没什么大不了的,但从理论上讲,也许可以改进。我该怎么办?将其移动到代码隐藏中?将它留在 ViewModel 中并使用 args 转换器?就这样放着?public void Window_DropFile(DragEventArgs e) {    if (e.Data.GetDataPresent(DataFormats.FileDrop)) {        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);        foreach (string file in files) {            ReadScriptFile(file);        }    }}public void Window_PreviewDragOver(DragEventArgs e) {    e.Effects = DragDropEffects.All;    e.Handled = true;}public void Header_PreviewLeftMouseButtonDown(IScriptViewModel sender, MouseButtonEventArgs e) {    if (sender == SelectedItem && sender.CanEditHeader && !sender.IsEditingHeader) {        sender.IsEditingHeader = true;        e.Handled = true;    }}
查看完整描述

3 回答

?
不负相思意

TA贡献1777条经验 获得超10个赞

一般来说:

你的 MVVM 视图模型应该只包含数据和命令。当然有很多例外,但请记住,基本上,它应该只包含与视图相关的命令和项目。

当事件处理程序应用于组件时,我看到了很多关于这一点的困惑。事情是; 当您在视图模型中放置 UI 组件的事件处理程序时,视图模型绑定到视图的实际实现(使用 UI 组件),而不是一般的“视图”。

根据经验; 你应该能够复制你的视图模型并在另一个实现中使用它,它应该只是编译。它不应该包含对 UI 元素本身的引用,或者通过事件处理等间接引用。


所以,是的,您应该将这些事件处理程序放在代码隐藏中,或者找到一个能够在视图/XAML 中处理它的框架或组件。从这样的事件中调用命令完全没问题。更实用的方法会说:将它们放在最有效的地方,并使您的代码最易读/易维护。如果你理解了 MVVM 的概念,你就会尽量减少这些混合模型的出现,这通常就足够了。


查看完整回答
反对 回复 2021-10-09
?
青春有我

TA贡献1784条经验 获得超8个赞

我会用附加属性做这样的事情。例如,对于 FileDrop,我将实现一个附加属性,如下所示:


public static class WindowExtensions

{

    public static readonly DependencyProperty ReadScriptFilesCommandProperty = DependencyProperty.RegisterAttached(

        "ReadScriptFilesCommand",

        typeof(ICommand),

        typeof(WindowExtensions),

        new PropertyMetadata(default(ICommand), OnReadScriptFilesCommandChanged));


    private static void OnReadScriptFilesCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    {

        Window window = d as Window;

        if (window == null)

            return;


        if (e.NewValue is ICommand)

        {

            window.Drop += WindowOnDrop;

        }

        if (e.OldValue != null)

        {

            window.Drop -= WindowOnDrop;

        }

    }


    private static void WindowOnDrop(object sender, DragEventArgs e)

    {

        Window window = sender as Window;

        if (window == null)

            return;

        if (e.Data.GetDataPresent(DataFormats.FileDrop))

        {

            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

            ICommand readScriptFilesCommand = GetReadScriptFilesCommand(window);

            readScriptFilesCommand.Execute(files);

        }

    }


    public static void SetReadScriptFilesCommand(DependencyObject element, ICommand value)

    {

        element.SetValue(ReadScriptFilesCommandProperty, value);

    }


    public static ICommand GetReadScriptFilesCommand(DependencyObject element)

    {

        return (ICommand)element.GetValue(ReadScriptFilesCommandProperty);

    }

}

所以你可以在你Window的视图中设置它并将它链接到ICommand你的视图模型中。该命令采用string[]并执行逻辑。


查看完整回答
反对 回复 2021-10-09
  • 3 回答
  • 0 关注
  • 146 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信