我正在尝试在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
最佳答案
自己在WPF中实现DragDrop并不是一件很有趣的事情,但是这当然是可能的,并且使用库的问题总是在某些时候受到限制。我附加了一个示例,该示例显示了如何将您的行为链接到 View 模型。如上所述,您需要手动启动DoDragDrop。
示例中未包含的内容:放置逻辑,该逻辑告诉您放置时发生的事情(如果DragDrop在同一列表框中,则对项目进行排序;如果DragDrop在同一列表框中,则对其进行排序)。如果您想要一个稍微复杂和完整的示例,请查看我的答案here。
Xml:
<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;
}
}
}
ViewModel:
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);
}
}
}
}
关于wpf - 拖放不起作用..要从其 View 中拖放某些对象时触发DragOver命令,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25015016/