我正在尝试在MVVM中实现拖放,但是当我尝试拖动项目时,事件不会被触发。但是,当我从外面拖动项目时,它会开始工作。
我想要第一种情况,让它在拖动时工作。有什么特别的方法吗?我正在使用行为和中继命令。
以下是我正在使用的代码,请告诉我错误的地方:
XAML
<Grid x:Name="MainGrid" Width="{Binding ElementName=ProjectWindow,Path=ActualWidth}">
<ListBox x:Name="icTodoList" Background="#FFF3800C" Canvas.Top="25" Height="600" Width="{Binding ElementName=gd,Path=ActualWidth}" BorderThickness="0" BorderBrush="{x:Null}">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FFF3800C" Opacity="0.2"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#FFF3800C" />
</ListBox.Resources>
<ListBox Name="InnerListBox" dd:DragOverBehaviour.DragOver="{Binding DragOver}" local2:PhasesDragDropViewModel.ListBox="{Binding ElementName=InnerListBox}" Margin="0,0,0,0" Height="550" AllowDrop="True" ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</ListBox>
</Grid>
模型类
public static class DragOverBehaviour
{
public static readonly DependencyProperty DragOver = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(UIElement.DragOverEvent, "DragOver", typeof(DragOverBehaviour));
public static void SetDragOver(DependencyObject o, ICommand value)
{
o.SetValue(DragOver, value);
}
public static ICommand GetDragOver(DependencyObject o)
{
return o.GetValue(DragOver) as ICommand;
}
}
查看模型
#region DragOverAction
private RelayCommand<object> m_cmdDragOver;
public ICommand DragOver
{
get { return m_cmdDragOver ?? (m_cmdDragOver = new RelayCommand<object>(DragOverAction, delegate { return true; })); }
}
private void DragOverAction(object sender)
{
}
#endregion
答案 0 :(得分:4)
在WPF中实现DragDrop并不是很有趣,但当然这一切都是可能的,并且使用库的问题在某些方面总是存在局限性。我附上了一个示例,展示了如何将您的行为链接到viewmodel。如上所述,您需要手动启动DoDragDrop。
示例中未包含的内容:drop逻辑,它告诉您drop上发生了什么(如果DragDrop在同一个列表框中,则重新排序项目,如果它在外面则添加)。如果您想要一个稍微复杂和完整的样本,请查看我的答案here。
的Xaml:
<UserControl x:Class="WpfApplication1.Controls.DragOverDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
xmlns:beh="clr-namespace:WpfApplication1.Behavior"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<UserControl.DataContext>
<vm:DragOverDemoViewModel />
</UserControl.DataContext>
<StackPanel x:Name="MainPanel">
<TextBlock Text="{Binding State}" Margin="5" />
<ListBox x:Name="icTodoList" Background="#FFF3800C" Canvas.Top="25" Height="600" BorderThickness="0" BorderBrush="{x:Null}">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FFF3800C" Opacity="0.2"/>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#FFF3800C" />
</ListBox.Resources>
<ListBox x:Name="InnerListBox" ItemsSource="{Binding Items}" Margin="0" Height="550" Width="250" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<i:Interaction.Behaviors>
<beh:DragDropBehavior DragOverCommand="{Binding DragOverCommand}" DropCommand="{Binding DropCommand}" />
</i:Interaction.Behaviors>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border MinHeight="30" MinWidth="100" BorderThickness="1" BorderBrush="DarkGray" Margin="2" >
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ListBox>
</StackPanel>
</UserControl>
DragDropBehavior:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace WpfApplication1.Behavior
{
public class DragDropBehavior : Behavior<ItemsControl>
{
private bool _isDragging;
private IDataObject _dataObject;
private Type _dataType;
public ICommand DragOverCommand { get { return (ICommand)GetValue(DragOverCommandProperty); } set { SetValue(DragOverCommandProperty, value); } }
public static readonly DependencyProperty DragOverCommandProperty = DependencyProperty.Register("DragOverCommand", typeof(ICommand), typeof(DragDropBehavior), new PropertyMetadata(null));
public ICommand DropCommand { get { return (ICommand)GetValue(DropCommandProperty); } set { SetValue(DropCommandProperty, value); } }
public static readonly DependencyProperty DropCommandProperty = DependencyProperty.Register("DropCommand", typeof(ICommand), typeof(DragDropBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
this.AssociatedObject.AllowDrop = true;
this.AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
this.AssociatedObject.PreviewMouseMove += AssociatedObject_PreviewMouseMove;
this.AssociatedObject.PreviewMouseLeftButtonUp += AssociatedObject_PreviewMouseLeftButtonUp;
base.OnAttached();
}
void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// get data from mouse position
ItemsControl itemsControl = (ItemsControl)sender;
Point p = e.GetPosition(itemsControl);
object data = itemsControl.GetDataObjectFromPoint(p);
if (data != null)
{
_dataType = data.GetType();
_dataObject = new DataObject(_dataType, data);
_isDragging = true; // valid data found, set dragging to true
}
}
void AssociatedObject_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (_isDragging)
{
// let viewmodel know of the drag
this.DragOverCommand.Execute(_dataObject.GetData(_dataType));
// execute drag
DragDropEffects eff = DragDrop.DoDragDrop(this.AssociatedObject, _dataObject, DragDropEffects.Copy | DragDropEffects.Move);
// thread waits for DragDrop to finish...
Drop();
}
}
void AssociatedObject_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_isDragging = false;
}
private void Drop()
{
// let viewmodel know of the drop
this.DropCommand.Execute(_dataObject.GetData(_dataType));
_isDragging = false;
}
}
}
视图模型:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1.ViewModels
{
public class DragOverDemoViewModel : NotifyBase
{
public class ItemModel : NotifyBase
{
public string Name { get { return base.GetValue(() => Name); } set { base.SetValue(() => Name, value); } }
}
public ObservableCollection<ItemModel> Items { get; private set; }
public ICommand DragOverCommand { get { return base.GetValue(() => DragOverCommand); } set { base.SetValue(() => DragOverCommand, value); } }
public ICommand DropCommand { get { return base.GetValue(() => DropCommand); } set { base.SetValue(() => DropCommand, value); } }
public string State { get { return base.GetValue(() => State); } set { base.SetValue(() => State, value); } }
public DragOverDemoViewModel()
{
this.Items = new ObservableCollection<ItemModel>()
{
new ItemModel() { Name = "Item 1"},
new ItemModel() { Name = "Item 2"},
new ItemModel() { Name = "Item 3"},
new ItemModel() { Name = "Item 4"},
new ItemModel() { Name = "Item 5"},
new ItemModel() { Name = "Item 6"},
new ItemModel() { Name = "Item 7"},
};
this.DragOverCommand = new ActionCommand<ItemModel>(DragOver);
this.DropCommand = new ActionCommand<ItemModel>(Drop);
}
private void DragOver(ItemModel item) { this.State = string.Format("Dragging {0}...", item.Name); }
private void Drop(ItemModel item) { this.State = string.Format("Dropped {0}.", item.Name); }
}
public class ActionCommand<T> : ICommand
{
public event EventHandler CanExecuteChanged;
private Action<T> _action;
public ActionCommand(Action<T> action)
{
_action = action;
}
public bool CanExecute(object parameter) { return true; }
public void Execute(object parameter)
{
if (_action != null)
{
var castParameter = (T)Convert.ChangeType(parameter, typeof(T));
_action(castParameter);
}
}
}
}
答案 1 :(得分:0)
首先,这就是我理解你的问题的方法(如果我错了,请纠正我):当您从列表框中的外部应用程序拖动对象时,DragOver
事件会触发。但是,当您从 inside 应用程序中拖动对象时,DragOver
事件不会触发。
如果要从应用程序中拖动对象,则需要将它们注册为拖动源:
using System.Windows;
using System.Windows.Input;
...
dragSourceControl.MouseMove += dragSourceControl_MouseMove;
...
private static void dragSourceControl_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed)
return;
var data = new DataObject();
data.SetData("some data");
DragDrop.DoDragDrop((UIElement)sender, data, DragDropEffects.Move);
}