MVVM 事件处理程序从何而来

我正在编写一个简单的 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;

    }

}


繁华开满天机
浏览 147回答 3
3回答

不负相思意

一般来说:你的 MVVM 视图模型应该只包含数据和命令。当然有很多例外,但请记住,基本上,它应该只包含与视图相关的命令和项目。当事件处理程序应用于组件时,我看到了很多关于这一点的困惑。事情是; 当您在视图模型中放置 UI 组件的事件处理程序时,视图模型绑定到视图的实际实现(使用 UI 组件),而不是一般的“视图”。根据经验; 你应该能够复制你的视图模型并在另一个实现中使用它,它应该只是编译。它不应该包含对 UI 元素本身的引用,或者通过事件处理等间接引用。所以,是的,您应该将这些事件处理程序放在代码隐藏中,或者找到一个能够在视图/XAML 中处理它的框架或组件。从这样的事件中调用命令完全没问题。更实用的方法会说:将它们放在最有效的地方,并使您的代码最易读/易维护。如果你理解了 MVVM 的概念,你就会尽量减少这些混合模型的出现,这通常就足够了。

青春有我

我会用附加属性做这样的事情。例如,对于 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[]并执行逻辑。
打开App,查看更多内容
随时随地看视频慕课网APP