拖放不工作..当你从视图中拖放一些对象时,想要触发DragOver命令

时间:2014-07-29 12:13:13

标签: wpf xaml mvvm drag-and-drop

我正在尝试在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

2 个答案:

答案 0 :(得分:4)

enter image description here

在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);
}