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

10-11 15:43