【问题标题】:Command Binding to Usercontrol Drag/Drop命令绑定到用户控件拖放
【发布时间】:2009-12-07 14:38:00
【问题描述】:

如何通过使用 WPF 中的命令模式来创建响应用户控件的拖放事件的 UI?

【问题讨论】:

    标签: wpf user-controls drag-and-drop command commandbinding


    【解决方案1】:

    在用户控件上

    实现一个有参数的命令。我将 ICommand 与 Josh Smiths RelayCommand 一起使用,但我对其进行了扩展以提供参数。 (此答案末尾的代码)

      /// <summary>
      /// Gets and Sets the ICommand that manages dragging and dropping.
      /// </summary>
      /// <remarks>The CanExecute will be called to determin if a drop can take place, the Executed is called when a drop takes place</remarks>
      public ICommand DragDropCommand {
         get { return (ICommand)GetValue(DragDropCommandProperty); }
         set { SetValue(DragDropCommandProperty, value); }
    

    现在您可以将视图模型绑定到此命令。

    为我们的实体拖动类型设置另一个属性(您可以对此进行硬编码),但我将此用户控件重复用于不同的事物,并且我不希望一个控件在放置时接受错误的实体类型。

      /// <summary>
      /// Gets and Sets the Name of the items we are dragging
      /// </summary>
      public String DragEntityType {
         get { return (String)GetValue(DragEntityTypeProperty); }
         set { SetValue(DragEntityTypeProperty, value); }
      }
    

    覆盖 OnPreviewLeftMouseButtonDown

       protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
          //find the item the mouse is over, i.e. the one you want to drag.
          var itemToDrag = FindItem(e);
    
          //move the selected items, using the drag entity type
          DataObject data = new DataObject(this.DragEntityType, itemToDrag);
          //use the helper class to initiate the drag
          DragDropEffects de = DragDrop.DoDragDrop(this, data, DragDropEffects.Move);
    
          //call the base
          base.OnPreviewMouseLeftButtonDown(e);
       }
    

    当您调用 DragDrop.DoDragDrop 时,将在适当的时候调用以下方法

    重写 OnDragOver 和 OnDragDrop 方法,并使用命令询问是否可以拖放

    protected override void OnDragOver(DragEventArgs e) {
    
         //if we can accept the drop
         if (this.DragDropCommand != null && this.DragDropCommand.CanExecute(e.Data)) {
    
            // Console.WriteLine(true);
         }
         //otherwise
         else {
            e.Effects = DragDropEffects.None;
            e.Handled = true;
         }
         base.OnDragOver(e);
      }
    
      protected override void OnDrop(DragEventArgs e) {
    
         if (this.DragDropCommand == null) { }
         //if we dont allow dropping on ourselves and we are trying to do it
         //else if (this.AllowSelfDrop == false && e.Source == this) { }
         else {
            this.DragDropCommand.Execute(e.Data);
         }
         base.OnDrop(e);
      }
    

    在视图模型中

    然后当你在视图模型中设置你的命令时,使用类似的东西,然后将命令绑定到你的用户控件

         this.MyDropCommand = new ExtendedRelayCommand((Object o) => AddItem(o), (Object o) => { return ItemCanBeDragged(o); });
    

    通常您是从一个用户控件拖动到另一个用户控件,因此您将为一个用户控件设置一个命令,为另一个用户控件设置一个命令,每个命令都有您可以接受的不同 DragEntityType。两个用户控件,一个用于拖动,一个用于放置,反之亦然。每个用户控件都有不同的 DragEntityType,因此您可以分辨出拖动的来源。

      private Boolean ItemCanBeDragged(object o) {
         Boolean returnValue = false;
    
         //do they have permissions to dragt
         if (this.HasPermissionToDrag) {
    
            IDataObject data = o as IDataObject;
    
            if (data == null) { }
            //this line looks up the DragEntityType
            else if (data.GetDataPresent("ItemDragEntityTypeForItemWeAreDragging")) {
               returnValue = true;
            }
         }
         return returnValue;
      }
    

    当我们放下时

      private void AddItem(object o) {
         IDataObject data = o as IDataObject;
    
         if (data == null) { }
         else {
            MyDataObject myData = data.GetData("ItemDragEntityTypeForItemWeAreDroppingHere") as MyDataObject ;
    
            if (myData == null) { }
            else {
                //do something with the dropped data
            }
         }
      }
    

    我可能遗漏了一些东西,但是这种技术让我可以询问视图模型是否可以拖动一个项目,并让我询问视图模型是否可以放下(如果视图模型将接受该项目)它的可绑定项,并且它很好地分离了视图/视图模型。如果您有任何问题,请随时提出。

    扩展中继命令,感谢 Josh Smith...

       /// <summary>
       /// A command whose sole purpose is to 
       /// relay its ExtendedFunctionality to other
       /// objects by invoking delegates. The
       /// default return value for the CanExecute
       /// method is 'true'.
       /// </summary>
       public class ExtendedRelayCommand : ICommand {
          #region Constructors
    
          /// <summary>
          /// Creates a new command that can always execute.
          /// </summary>
          /// <param name="execute">The execution logic.</param>
          public ExtendedRelayCommand(Action<Object> execute)
             : this(execute, null) {
          }
    
          /// <summary>
          /// Creates a new command.
          /// </summary>
          /// <param name="execute">The execution logic.</param>
          /// <param name="canExecute">The execution status logic.</param>
          public ExtendedRelayCommand(Action<Object> execute, Func<Object, bool> canExecute) {
             if (execute == null)
                throw new ArgumentNullException("execute");
    
             _execute = execute;
             _canExecute = canExecute;
          }
    
          #endregion // Constructors
    
          #region ICommand Members
    
          [DebuggerStepThrough]
          public bool CanExecute(object parameter) {
             return _canExecute == null ? true : _canExecute(parameter);
          }
    
          public event EventHandler CanExecuteChanged {
             add {
                if (_canExecute != null)
                   CommandManager.RequerySuggested += value;
             }
             remove {
                if (_canExecute != null)
                   CommandManager.RequerySuggested -= value;
             }
          }
    
          public void Execute(object parameter) {
             _execute(parameter);
          }
    
          #endregion // ICommand Members
    
          #region Fields
    
          readonly Action<Object> _execute;
          readonly Func<Object, bool> _canExecute;
    
          #endregion // Fields
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-04
      • 1970-01-01
      • 2013-02-11
      • 2018-12-03
      • 1970-01-01
      相关资源
      最近更新 更多