使用用户控件执行拖放时 C# WPF UI 无响应



我遇到了 C# wpf 拖放问题。 我创建了一个非常简单的项目,其中包括一个用户控件、几个用于保存数据的类和一个用于承载用户控件的多个副本(使用绑定的 ItemsControl(的窗体。 当我将控件拖动到窗体上时,会触发拖放,可观察集合会更新,但 UI 不会反映更改,并且未来的事件似乎不起作用。 滚动添加项目按钮甚至不会显示滚动效果。 当然,我正在做一些愚蠢的事情,但我似乎看不到它是什么。

下面的代码(主要来自Microsoft示例(

简单数据类

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DragDropControl.Model
{
public class SimpleDataClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _groupName = string.Empty;
private ObservableCollection<SimpleSubDataClass> _titles = new ObservableCollection<SimpleSubDataClass>();
public string GroupName
{
get { return _groupName; }
set
{
if (_groupName != value)
{
_groupName = value;
RaisePropertyChangedEvent("GroupName");
}
}
}
public ObservableCollection<SimpleSubDataClass> Titles
{
get { return _titles; }
set
{
if (_titles != value)
{
_titles = value;
RaisePropertyChangedEvent("Titles");
}
}
}
private void RaisePropertyChangedEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

简单子数据类

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DragDropControl.Model
{
public class SimpleSubDataClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _title = string.Empty;
public string Title
{
get { return _title; }
set
{
if (_title != value)
{
_title = value;
RaisePropertyChanged("Title");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public SimpleSubDataClass(string title)
{
Title = title;
}
}
}

DDControl - XAML

<UserControl x:Class="DragDropControl.DDControl"
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:local="clr-namespace:DragDropControl"
mc:Ignorable="d" 
d:DesignHeight="300" d:DesignWidth="300"
x:Name="CurrentControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Name="txtGroupName" Grid.Row="0" Text="{Binding ElementName=CurrentControl, Path=ThisData.GroupName}"/>
<ListBox Name="lstTitles" Grid.Row="1" ItemsSource="{Binding ElementName=CurrentControl, Path=ThisData.Titles}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Name="lblTitle" Content="{Binding Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>

DDControl - 代码隐藏

using DragDropControl.Model;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace DragDropControl
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class DDControl : UserControl
{
public static readonly DependencyProperty ThisDataProperty = DependencyProperty.Register( "ThisData",
                        typeof(SimpleDataClass),
                        typeof(DDControl),
                        new PropertyMetadata(new SimpleDataClass()));
public SimpleDataClass ThisData
{
get { return (SimpleDataClass)GetValue(ThisDataProperty); }
set { SetValue(ThisDataProperty, value); }
}

public DDControl()
{
InitializeComponent();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
DataObject data = new DataObject(this.ThisData);
DragDrop.DoDragDrop(this, data, DragDropEffects.Move);
}
}
protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
{
base.OnGiveFeedback(e);
if (e.Effects.HasFlag(DragDropEffects.Move))
Mouse.SetCursor(Cursors.Pen);
e.Handled = true;
}
}
}

主窗口 - Xaml

<Window x:Class="DragDropUserControlWithTextBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DragDropUserControlWithTextBox"
xmlns:ddc="clr-namespace:DragDropControl;assembly=DragDropControl"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<StackPanel Name="stkMain" Background="Gray" Orientation="Horizontal" Drop="stkMain_Drop" AllowDrop="true">
<ItemsControl Name="icColumns" Background="Red">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Name="stkItemsControlPanel" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ddc:DDControl Background="{x:Null}" ThisData="{Binding}"/><!-- MouseMove="DDControl_MouseMove" GiveFeedback="DDControl_GiveFeedback"/>-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Name="btnAddData" Content="Add Data" Click="btnAddData_Click"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Window>

主窗口 - 代码隐藏

using DragDropControl.Model;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace DragDropUserControlWithTextBox
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<SimpleDataClass> _data = new ObservableCollection<SimpleDataClass>();
public MainWindow()
{
InitializeComponent();
CreateTestData();
}
private void CreateTestData()
{
SimpleDataClass tempSDC1 = new SimpleDataClass();
tempSDC1.GroupName = "First Item";
tempSDC1.Titles.Add(new SimpleSubDataClass("Title 1_1"));
tempSDC1.Titles.Add(new SimpleSubDataClass("Title 1_2"));
tempSDC1.Titles.Add(new SimpleSubDataClass("Title 1_3"));
tempSDC1.Titles.Add(new SimpleSubDataClass("Title 1_4"));
tempSDC1.Titles.Add(new SimpleSubDataClass("Title 1_5"));
SimpleDataClass tempSDC2 = new SimpleDataClass();
tempSDC2.GroupName = "Second Item";
tempSDC2.Titles.Add(new SimpleSubDataClass("Title 2_1"));
tempSDC2.Titles.Add(new SimpleSubDataClass("Title 2_2"));
tempSDC2.Titles.Add(new SimpleSubDataClass("Title 2_3"));
tempSDC2.Titles.Add(new SimpleSubDataClass("Title 2_4"));
tempSDC2.Titles.Add(new SimpleSubDataClass("Title 2_5"));
_data.Add(tempSDC1);
_data.Add(tempSDC2);
this.icColumns.ItemsSource = _data;
}
private void stkMain_Drop(object sender, DragEventArgs e)
{
if (e.Handled == false)
{
if (e.Data.GetDataPresent(typeof(SimpleDataClass)))
{
SimpleDataClass tempData = (SimpleDataClass)e.Data.GetData(typeof(SimpleDataClass));
_data.Add(tempData);
}
e.Effects.HasFlag(DragDropEffects.None);
Mouse.SetCursor(Cursors.Arrow);
e.Handled = true;
}
}
private void btnAddData_Click(object sender, RoutedEventArgs e)
{
SimpleDataClass tempData = new SimpleDataClass();
tempData.GroupName = "Amazing Test";
tempData.Titles.Add(new SimpleSubDataClass("AT_1"));
tempData.Titles.Add(new SimpleSubDataClass("AT_2"));
tempData.Titles.Add(new SimpleSubDataClass("AT_3"));
_data.Add(tempData);
}
}
}

我换成了使用本 WPF 教程中描述的拖放方法。 当您拖放带有文本框的用户控件时,它仍然存在一个问题(假设它将用于任何被命中启用的控件(,它将创建正在拖动的项的第二个实例,但这很容易解决,只需在检测到控件即将被拖动时将启用状态设置为 false,并在删除控件时再次启用它。 可能是一个黑客,但一个有效的。

对于拖放,请创建一个行为并处理行为中的事件,以避免 UI 线程冻结情况。检查以下链接将对您的方案有用。 https://www.telerik.com/blogs/adding-drag-and-drop-to-wpf-listboxes-thanks-telerik!

最新更新