[英]C# WPF UI unresponsive when performing drag drop using user control
我遇到了C#wpf拖放問題。 我創建了一個非常簡單的項目,其中包括一個用戶控件,幾個用於保存數據的類以及一個用於承載用戶控件的多個副本的表單(使用綁定的ItemsControl)。 當我將控件拖動到窗體上時,將觸發拖放操作,observablecollection已更新,但UI無法反映更改,以后的事件似乎也無法正常工作。 將鼠標懸停在“添加項目”按鈕上甚至不會顯示滾動效果。 當然,我在做一些愚蠢的事情,但似乎看不到它是什么。
下面的代碼(主要來自Microsoft Example )
SimpleDataClass
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));
}
}
}
SimpleSubDataClass
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;
}
}
}
MainWindow-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>
MainWindow-后面的代碼
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,然后在將其放下時再次將其啟用即可。 可能是一種駭客,但行之有效。
對於拖放操作,請創建一個Behavior並處理Behavior中的事件,以避免UI線程凍結情況。 檢查以下鏈接將對您的情況有用。 https://www.telerik.com/blogs/adding-drag-and-drop-to-wpf-listboxes-thanks-telerik !
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.