.net 如何在不违反 MVVM 原则的情况下处理拖放?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5916154/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 15:32:49  来源:igfitidea点击:

How to handle drag/drop without violating MVVM principals?

.netwpfmvvmdrag-and-drop

提问by Night Walker

Currently I have in my XAML

目前我在我的 XAML 中有

<TabControl  
    AllowDrop="True"
    PreviewDragOver="DragOver"
    PreviewDrop="Drop" />

All of my drag/drop code exists within the codebehind of my View, rather than within my ViewModel.

我所有的拖放代码都存在于我的视图的代码隐藏中,而不是我的视图模型中。

How can I handle drag/drop in my ViewModel without adding any dependencies on the View?

如何在不添加任何对视图的依赖的情况下处理我的 ViewModel 中的拖/放?

回答by default.kramer

There are libraries for this such as gongand similar snippets on various blog articles.

在各种博客文章中都有用于此的库,例如和类似的片段。

However, you shouldn't get too hung up on having absolutely no code-behind. For example, this is still MVVM in my book:

但是,您不应该太拘泥于完全没有代码隐藏。例如,这仍然是我书中的 MVVM:

void ButtonClicked(object sender, EventArgs e)
{
    ((MyViewModel) this.DataContext).DoSomething();
}

A command binding might be a better choice, but the logic is definitely in the viewmodel. With something like Drag and Drop, it's more variable where you want to draw the line. You can have code-behind interpret the Drag Args and call methods on the viewmodel when appropriate.

命令绑定可能是更好的选择,但逻辑肯定在视图模型中。使用诸如拖放之类的东西,在您想要画线的地方更加可变。您可以在适当的时候让代码隐藏解释 Drag Args 并调用视图模型上的方法。

回答by Asheh

Here is some code I wrote that allows you to drag and drop files onto a control without violating MVVM. It could easily be modified to pass the actual object instead of a file.

这是我编写的一些代码,允许您将文件拖放到控件上而不会违反 MVVM。可以很容易地修改它以传递实际对象而不是文件。

/// <summary>
/// IFileDragDropTarget Interface
/// </summary>
public interface IFileDragDropTarget
{
    void OnFileDrop(string[] filepaths);
}

/// <summary>
/// FileDragDropHelper
/// </summary>
public class FileDragDropHelper
{
    public static bool GetIsFileDragDropEnabled(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFileDragDropEnabledProperty);
    }

    public static void SetIsFileDragDropEnabled(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFileDragDropEnabledProperty, value);
    }

    public static bool GetFileDragDropTarget(DependencyObject obj)
    {
        return (bool)obj.GetValue(FileDragDropTargetProperty);
    }

    public static void SetFileDragDropTarget(DependencyObject obj, bool value)
    {
        obj.SetValue(FileDragDropTargetProperty, value);
    }

    public static readonly DependencyProperty IsFileDragDropEnabledProperty =
            DependencyProperty.RegisterAttached("IsFileDragDropEnabled", typeof(bool), typeof(FileDragDropHelper), new PropertyMetadata(OnFileDragDropEnabled));

    public static readonly DependencyProperty FileDragDropTargetProperty =
            DependencyProperty.RegisterAttached("FileDragDropTarget", typeof(object), typeof(FileDragDropHelper), null);

    private static void OnFileDragDropEnabled(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue == e.OldValue) return;
        var control = d as Control;
        if (control != null) control.Drop += OnDrop;
    }

    private static void OnDrop(object _sender, DragEventArgs _dragEventArgs)
    {
        DependencyObject d = _sender as DependencyObject;
        if (d == null) return;
        Object target = d.GetValue(FileDragDropTargetProperty);
        IFileDragDropTarget fileTarget = target as IFileDragDropTarget;
        if (fileTarget != null)
        {
            if (_dragEventArgs.Data.GetDataPresent(DataFormats.FileDrop))
            {
                fileTarget.OnFileDrop((string[])_dragEventArgs.Data.GetData(DataFormats.FileDrop));
            }
        }
        else
        {
            throw new Exception("FileDragDropTarget object must be of type IFileDragDropTarget");
        }
    }
}

Usage:

用法:

<ScrollViewer AllowDrop="True" Background="Transparent" utility:FileDragDropHelper.IsFileDragDropEnabled="True" utility:FileDragDropHelper.FileDragDropTarget="{Binding}"/>

Ensure the DataContext inherits from IFileDragDropTarget and implements the OnFileDrop.

确保 DataContext 从 IFileDragDropTarget 继承并实现 OnFileDrop。

public class MyDataContext : ViewModelBase, IFileDragDropTarget
{
    public void OnFileDrop(string[] filepaths)
    {
        //handle file drop in data context
    }
}

回答by Amen Jlili

This is just an additional answer that ports @Asheh's answer's to VB.NET for VB developers.

这只是将@Asheh 的答案移植到 VB.NET 以供 VB 开发人员使用的附加答案。

Imports System.Windows

Interface IFileDragDropTarget

    Sub OnFileDrop(ByVal filepaths As String())

End Interface

Public Class FileDragDropHelper

    Public Shared Function GetIsFileDragDropEnabled(ByVal obj As DependencyObject) As Boolean
        Return CBool(obj.GetValue(IsFileDragDropEnabledProperty))
    End Function

    Public Shared Sub SetIsFileDragDropEnabled(ByVal obj As DependencyObject, ByVal value As Boolean)
        obj.SetValue(IsFileDragDropEnabledProperty, value)
    End Sub

    Public Shared Function GetFileDragDropTarget(ByVal obj As DependencyObject) As Boolean
        Return CBool(obj.GetValue(FileDragDropTargetProperty))
    End Function

    Public Shared Sub SetFileDragDropTarget(ByVal obj As DependencyObject, ByVal value As Boolean)
        obj.SetValue(FileDragDropTargetProperty, value)
    End Sub

    Public Shared ReadOnly IsFileDragDropEnabledProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsFileDragDropEnabled", GetType(Boolean), GetType(FileDragDropHelper), New PropertyMetadata(AddressOf OnFileDragDropEnabled))

    Public Shared ReadOnly FileDragDropTargetProperty As DependencyProperty = DependencyProperty.RegisterAttached("FileDragDropTarget", GetType(Object), GetType(FileDragDropHelper), Nothing)

    Shared WithEvents control As Windows.Controls.Control
    Private Shared Sub OnFileDragDropEnabled(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        If e.NewValue = e.OldValue Then Return
        control = TryCast(d, Windows.Controls.Control)
        If control IsNot Nothing Then
            AddHandler control.Drop, AddressOf OnDrop
        End If
    End Sub

    Private Shared Sub OnDrop(ByVal _sender As Object, ByVal _dragEventArgs As DragEventArgs)
        Dim d As DependencyObject = TryCast(_sender, DependencyObject)
        If d Is Nothing Then Return
        Dim target As Object = d.GetValue(FileDragDropTargetProperty)
        Dim fileTarget As IFileDragDropTarget = TryCast(target, IFileDragDropTarget)
        If fileTarget IsNot Nothing Then
            If _dragEventArgs.Data.GetDataPresent(DataFormats.FileDrop) Then
                fileTarget.OnFileDrop(CType(_dragEventArgs.Data.GetData(DataFormats.FileDrop), String()))
            End If
        Else
            Throw New Exception("FileDragDropTarget object must be of type IFileDragDropTarget")
        End If
    End Sub
End Class

回答by fatty

This might also be of some help to you. The attached command behavior library allows you to convert any event(s) into a command which will more closely adhere to the MVVM framework.

这也可能对您有所帮助。附加的命令行为库允许您将任何事件转换为更符合 MVVM 框架的命令。

http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/

http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/

Using this is extremely easy. And has saved my bacon numerous times

使用它非常容易。并无数次救了我的培根

Hope this helps

希望这可以帮助