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

发布于 2024-10-13 04:32:36 字数 6798 浏览 1 评论 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>

和隐藏代码:

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

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

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>

隐藏的 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 );
        }
    }
}

I have a user control that contains two text boxes, as well as some other controls. I want to be able to drag/drop a complex type onto this control, and I want the entire control to be a drop target, including the textboxes and space around the composited controls. When the data is dropped, it is split apart into component fields, each represented by the controls in the user control.

The problem I am having is that the textboxes (if I set AllowDrop to true) are trying to do their own drag drop thing, and will individually accept only the text format of the drop data. If I set AllowDrop to false on the textboxes, the drop is disabled the for the textboxes altogether. I can drag my complex data to labels, checkboxes etc, and it behaves exactly like I expect it should.

In addition the space around the other controls does not seem to be considered a valid drop target.

Any ideas how to make the text boxes behave as the controls (such as the labels, checkbox or combobox), and why the grid is not being considered a valid drop target?

Source for the user control:

<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>

and code behind:

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

And for the main window that hosts the user control and a drag source...

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>

C# code behind:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乞讨 2024-10-20 04:32:36

看起来我可以通过单独挂钩文本框的拖/放事件来获得我想要的行为:

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

Its looks like I can get the behavior I want by hooking the drag/drop events of the text boxes individually:

    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;
    }
眼眸 2024-10-20 04:32:36

8 年后我在这里说这对我有帮助。此的 MVVM 版本:

XAML

<i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewDragEnter">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
    </i:EventTrigger>
    <i:EventTrigger EventName="PreviewDragOver">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
    </i:EventTrigger>
    <i:EventTrigger EventName="PreviewDrop">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxDrop"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

ViewModel

public void TextBoxIgnore(object sender, DragEventArgs args)
{
    args.Handled = true;
}

public void TextBoxDrop(object sender, DragEventArgs args)
{
    // handle the drop here.
}

注意:使用以下...

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

I'm here 8 years later to say this helped me. The MVVM version of this:

XAML

<i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewDragEnter">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
    </i:EventTrigger>
    <i:EventTrigger EventName="PreviewDragOver">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
    </i:EventTrigger>
    <i:EventTrigger EventName="PreviewDrop">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxDrop"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

ViewModel

public void TextBoxIgnore(object sender, DragEventArgs args)
{
    args.Handled = true;
}

public void TextBoxDrop(object sender, DragEventArgs args)
{
    // handle the drop here.
}

Note: Using the following...

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文