How to handle drag/drop without violating MVVM principals?

前端 未结 5 687
时光说笑
时光说笑 2020-12-24 07:40

Currently I have in my XAML


All of

5条回答
  •  旧巷少年郎
    2020-12-24 08:01

    Here is a solution a bit more generic, out-of-the-box and easier than Mustafa's one, with a single DependencyProperty

    1. Copy this interface in your projet and
    public interface IFilesDropped
    {
        void OnFilesDropped(string[] files);
    }
    
    1. Make you ViewModel implement the interface
    public class SomeViewModel : IFilesDropped
    {
        public void OnFilesDropped(string[] files)
        {
            // Implement some logic here
        }
    }
    
    1. Copy this generic extension in your project
    public class DropFilesBehaviorExtension
    {
        public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
            "IsEnabled", typeof(bool), typeof(DropFilesBehaviorExtension), new FrameworkPropertyMetadata(default(bool), OnPropChanged)
            {
                BindsTwoWayByDefault = false,
            });
    
        private static void OnPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is FrameworkElement fe))
                throw new InvalidOperationException();
            if ((bool)e.NewValue)
            {
                fe.AllowDrop = true;
                fe.Drop += OnDrop;
                fe.PreviewDragOver += OnPreviewDragOver;
            }
            else
            {
                fe.AllowDrop = false;
                fe.Drop -= OnDrop;
                fe.PreviewDragOver -= OnPreviewDragOver;
            }
        }
    
        private static void OnPreviewDragOver(object sender, DragEventArgs e)
        {
            // NOTE: PreviewDragOver subscription is required at least when FrameworkElement is a TextBox
            // because it appears that TextBox by default prevent Drag on preview...
            e.Effects = DragDropEffects.Move;
            e.Handled = true;
        }
    
        private static void OnDrop(object sender, DragEventArgs e)
        {
            var dataContext = ((FrameworkElement)sender).DataContext;
            if (!(dataContext is IFilesDropped filesDropped))
            {
                if (dataContext != null)
                    Trace.TraceError($"Binding error, '{dataContext.GetType().Name}' doesn't implement '{nameof(IFilesDropped)}'.");
                return;
            }
    
            if (!e.Data.GetDataPresent(DataFormats.FileDrop))
                return;
    
            if (e.Data.GetData(DataFormats.FileDrop) is string[] files)
                filesDropped.OnFilesDropped(files);
        }
    
        public static void SetIsEnabled(DependencyObject element, bool value)
        {
            element.SetValue(IsEnabledProperty, value);
        }
    
        public static bool GetIsEnabled(DependencyObject element)
        {
            return (bool)element.GetValue(IsEnabledProperty);
        }
    }
    
    1. Enable the Drop files behavior to the UI components of you choice (here a TextBox)
    
    

    Happy drops !

提交回复
热议问题