拖放到具有多个文本框的复合用户控件上

Dav*_*vid 4 .net c# wpf wpf-controls c#-4.0

我有一个包含两个文本框以及其他一些控件的用户控件。我希望能够将复杂类型拖放到此控件上,并且希望整个控件成为放置目标,包括文本框和组合控件周围的空间。删除数据后,会将其拆分为组件字段,每个字段由用户控件中的控件表示。

我遇到的问题是,文本框(如果我将AllowDrop设置为true)正在尝试做自己的拖放操作,并且将仅接受拖放数据的文本格式。如果在文本框中将AllowDrop设置为false,则完全禁用了文本框的放置。我可以将复杂的数据拖到标签,复选框等中,并且其行为与我期望的完全一样。

此外,其他控件周围的空间似乎不被视为有效的放置目标。

关于如何使文本框充当控件(例如标签,复选框或组合框)的任何想法,为什么不将网格视为有效的放置目标?

用户控件的来源:

<UserControl x:Class="DragDropTester.CompositeControl"
         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" 
         mc:Ignorable="d" 
         d:DesignHeight="226" d:DesignWidth="428" AllowDrop="True">
    <Grid AllowDrop="True">        
        <TextBox Height="23" Margin="115,12,12,0" Name="textBox1" VerticalAlignment="Top" AllowDrop="False" />
        <Label Content="TextBox 1:" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" Width="97" />
        <TextBox Height="23" Margin="115,41,12,0" Name="textBox2" VerticalAlignment="Top" AllowDrop="False" />
        <Label Content="TextBox 2:" Height="28" HorizontalAlignment="Left" Margin="12,41,0,0" Name="label2" VerticalAlignment="Top" Width="97" />
        <CheckBox Content="CheckBox" Height="16" Margin="115,70,150,0" Name="checkBox1" VerticalAlignment="Top" />
        <ComboBox Height="23" Margin="115,92,12,0" Name="comboBox1" VerticalAlignment="Top" />
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

和后面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DragDropTester {
    /// <summary>
    /// Interaction logic for CompositeControl.xaml
    /// </summary>
    public partial class CompositeControl : UserControl {

        public CompositeControl() {
            InitializeComponent();

            PreviewDragEnter += new DragEventHandler(CompositeControl_DragEnter);
            this.PreviewDragOver += new DragEventHandler(CompositeControl_DragEnter);

            Drop += new DragEventHandler(CompositeControl_Drop);
        }

        void CompositeControl_Drop(object sender, DragEventArgs e) {
            var complex = e.Data.GetData("ComplexDragData") as ComplexDragData;
            if (complex != null) {
                this.textBox1.Text = complex.Text1;
                this.textBox2.Text = complex.Text2;
                this.checkBox1.IsChecked = complex.BoolValue;
            }
        }

        void CompositeControl_DragEnter(object sender, DragEventArgs e) {
            var complex = e.Data.GetData("ComplexDragData") as ComplexDragData;
            if (complex != null) {
                e.Effects = DragDropEffects.Link;
            } else {
                e.Effects = DragDropEffects.None;
            }

            e.Handled = true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于承载用户控件和拖动源的主窗口...

XAML:

<Window x:Class="DragDropTester.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:DragDropTester"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="40" />
        </Grid.RowDefinitions>
        <src:CompositeControl />
        <Label Content="Drag Source" Grid.Row="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="5" Background="LightGray" Name="lblDragSource" />
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

后面的C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DragDropTester {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {

        private Point _startPoint;
        private bool _IsDragging;

        public MainWindow() {
            InitializeComponent();

            lblDragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(lblDragSource_PreviewMouseLeftButtonDown);
            lblDragSource.PreviewMouseMove += new MouseEventHandler(lblDragSource_PreviewMouseMove);
        }

        void lblDragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            _startPoint = e.GetPosition(sender as IInputElement);
        }

        void lblDragSource_PreviewMouseMove(object sender, MouseEventArgs e) {

            if (_startPoint == null) {
                return;
            }

            if (e.LeftButton == MouseButtonState.Pressed && !_IsDragging) {
                Point position = e.GetPosition(sender as IInputElement);
                if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance) {
                    StartDrag(sender as DependencyObject);
                }
            }            
        }

        private void StartDrag(DependencyObject dragSource) {
            var data = new DataObject();
            var dragData = new ComplexDragData { Text1 = "This is text1", Text2 = "This is text2", BoolValue = true };
            data.SetData("ComplexDragData", dragData);
            data.SetData(DataFormats.Text, dragData.ToString());

            try {
                _IsDragging = true;
                DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Copy | DragDropEffects.Link);
            } finally {
                _IsDragging = false;
            }

        }
    }

    public class ComplexDragData {
        public String Text1 { get; set; }
        public String Text2 { get; set; }
        public bool BoolValue { get; set; }

        public override string ToString() {
            return string.Format("text1: {0} text2: {1} Bool: {2}", Text1, Text2, BoolValue );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*vid 5

看起来我可以通过分别挂接文本框的拖放事件来获得所需的行为:

    public CompositeControl() {
        InitializeComponent();

        PreviewDragEnter += new DragEventHandler(CompositeControl_DragEnter);
        PreviewDragOver += new DragEventHandler(CompositeControl_DragEnter);

        textBox1.PreviewDragEnter += new DragEventHandler(textBox_PreviewDragEnter);
        textBox1.PreviewDragOver += new DragEventHandler(textBox_PreviewDragEnter);
        textBox1.PreviewDrop += new DragEventHandler(CompositeControl_Drop);

        textBox2.PreviewDragEnter += new DragEventHandler(textBox_PreviewDragEnter);
        textBox2.PreviewDragOver += new DragEventHandler(textBox_PreviewDragEnter);
        textBox2.PreviewDrop += new DragEventHandler(CompositeControl_Drop);

        Drop += new DragEventHandler(CompositeControl_Drop);
    }

    void textBox_PreviewDragEnter(object sender, DragEventArgs e) {
        e.Handled = true;
    }
Run Code Online (Sandbox Code Playgroud)