目前我的XAML
<TabControl
AllowDrop="True"
PreviewDragOver="DragOver"
PreviewDrop="Drop" />
我的所有拖放代码都存在于我的View的代码隐藏中,而不是在我的ViewModel中。
如何在ViewModel中处理拖放操作而不在View上添加任何依赖项?
答案 0 :(得分:18)
有各种类型的库,例如gong以及各种博客文章中的类似代码段。
但是,你绝不应该完全没有代码隐藏。例如,我的书中仍然是MVVM:
void ButtonClicked(object sender, EventArgs e)
{
((MyViewModel) this.DataContext).DoSomething();
}
命令绑定可能是更好的选择,但逻辑肯定在viewmodel中。使用Drag和Drop之类的东西,你想要绘制线条的位置更加多变。您可以在适当的时候使用代码隐藏解释Drag Args并在viewmodel上调用方法。
答案 1 :(得分:12)
以下是我编写的一些代码,它允许您在不违反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");
}
}
}
用法:
<ScrollViewer AllowDrop="True" Background="Transparent" utility:FileDragDropHelper.IsFileDragDropEnabled="True" utility:FileDragDropHelper.FileDragDropTarget="{Binding}"/>
确保DataContext继承自IFileDragDropTarget并实现OnFileDrop。
public class MyDataContext : ViewModelBase, IFileDragDropTarget
{
public void OnFileDrop(string[] filepaths)
{
//handle file drop in data context
}
}
答案 2 :(得分:0)
这也可能对你有所帮助。附加的命令行为库允许您将任何事件转换为更紧密地遵守MVVM框架的命令。
http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/
使用它非常容易。并多次保存我的培根
希望这有帮助
答案 3 :(得分:0)
对于VB开发人员来说,这只是一个额外的答案,即@asheh对VB.NET的回答。
$router->get('/route-name', 'myController@myMethodName');
答案 4 :(得分:0)
这里有一个解决方案,它比Mustafa的解决方案更为通用,开箱即用,并且更简单,只需一个DependencyProperty
public interface IFilesDropped
{
void OnFilesDropped(string[] files);
}
public class SomeViewModel : IFilesDropped
{
public void OnFilesDropped(string[] files)
{
// Implement some logic here
}
}
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);
}
}
<TextBox ns:DropFilesBehaviorExtension.IsEnabled ="True" />
快乐滴!