在运行时动态地将EventSetter添加到现有的分层数据模板

时间:2016-11-05 11:32:19

标签: c# wpf xaml treeview eventsetter

我有一个WPF TreeView控件,它通过绑定获取分层数据。要控制控件中的可视输出,我使用Hierarchical Data TemplatesDataContext的{​​{1}}是自定义类的TreeView,可以容纳不同类型的子类型。

ObservableCollection

由于public class PaletteGroup { public string Name { get; set; } public ObservableCollection<Palette> Palettes { get; set; } public ObservableCollection<PaletteGroup> PaletteGroups { get; set; } public IList Children { get { return new CompositeCollection() { new CollectionContainer() { Collection = Palettes }, new CollectionContainer() { Collection = PaletteGroups } }; } } } public class Palette { public string Name { get; set; } } 类可以容纳PaletteGroupPalette类型的子项,因此我使用PaletteGroupCompositeCollection组合在一个层次结构中ObservableCollection中的视觉输出,因为我的类可以有你想要的子节点级别。

视觉输出本身在我的xaml文件中定义,我使用这两个类的TreeView属性来显示对象的名称:

Name

正如您所看到的,我还将<local:DragDropDecorator AllowDrop="True" AllowPaletteItems="False" AllowPaletteGroups="True" AllowPalettes="True"> <TreeView Margin="10,10,10,40" Name="PaletteStructureView" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" MouseRightButtonUp="PalettesListBoxMouseRightButtonUp" ItemsSource="{Binding LoadedPaletteGroups}"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:PaletteGroup}" ItemsSource="{Binding Children}"> <TextBlock Foreground="DarkGreen" Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type local:Palette}"> <TextBlock Foreground="DarkBlue" Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView> </local:DragDropDecorator> 控件包装在名为TreeView的Drag&amp; Drop操作的自定义类中,其中我在运行时添加了控件的所有必要事件。由于我使用了很多不同的控件,我厌倦了总是将事件绑定到xaml文件中的控件。此类的DragDropDecorator事件如下所示:

Loaded

这对于private void DragableItemsControl_Loaded( object sender, RoutedEventArgs e ) { if (!(base.DecoratedUIElement is ItemsControl)) throw new InvalidCastException(string.Format("DragDragDecorator cannot have child of type {0}", Child.GetType())); ItemsControl itemsControl = (ItemsControl)DecoratedUIElement; itemsControl.AllowDrop = AllowDrop; itemsControl.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonDown); itemsControl.PreviewMouseMove += new MouseEventHandler(ItemsControl_PreviewMouseMove); itemsControl.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonUp); itemsControl.PreviewDrop += new DragEventHandler(ItemsControl_PreviewDrop); itemsControl.PreviewQueryContinueDrag += new QueryContinueDragEventHandler(ItemsControl_PreviewQueryContinueDrag); itemsControl.PreviewDragEnter += new DragEventHandler(ItemsControl_PreviewDragEnter); itemsControl.PreviewDragOver += new DragEventHandler(ItemsControl_PreviewDragOver); itemsControl.DragLeave += new DragEventHandler(ItemsControl_DragLeave); } 控件来说绝对正常,这也是我项目的需要。但是我对ListBox控件非常困难,因为事件仅针对TreeView中的最高节点引发,即使我尝试对某些孩子进行拖放操作。

首先,我尝试将所有事件添加到TreeView。这适用于第一级子节点,但忽略更深的节点结构以及最上面的节点。

然后我尝试将所有事件添加到TreeView.ItemContainerStyle类的Hierarchical Data Template事件中的Loaded

DragDropDecorator

使用此代码,由于已经密封的模板对象,我得到if (itemsControl.GetType() == typeof(TreeView)) { foreach (object item in itemsControl.Resources.Keys) { var hdt = itemsControl.FindResource(item); if (hdt != null & hdt.GetType() == typeof(HierarchicalDataTemplate)) { var newHdt = (HierarchicalDataTemplate)hdt; var test = new Style(); test.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonDown))); test.Setters.Add(new EventSetter(PreviewMouseMoveEvent, new MouseEventHandler(ItemsControl_PreviewMouseMove))); test.Setters.Add(new EventSetter(PreviewMouseLeftButtonUpEvent, new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonUp))); test.Setters.Add(new EventSetter(PreviewDropEvent, new DragEventHandler(ItemsControl_PreviewDrop))); test.Setters.Add(new EventSetter(PreviewQueryContinueDragEvent, new QueryContinueDragEventHandler(ItemsControl_PreviewQueryContinueDrag))); test.Setters.Add(new EventSetter(PreviewDragEnterEvent, new DragEventHandler(ItemsControl_PreviewDragEnter))); test.Setters.Add(new EventSetter(PreviewDragOverEvent, new DragEventHandler(ItemsControl_PreviewDragOver))); test.Setters.Add(new EventSetter(DragLeaveEvent, new DragEventHandler(ItemsControl_DragLeave))); newHdt.ItemContainerStyle = test; } } }

所以我的问题是:

  • 如何在运行时将EventSetters添加到已存在的InvalidOperationException
  • 这是正确的做法,还是我有 其他选择让这更优雅?

经过几个小时尝试不同的方法并在互联网上搜索解决方案后,我现在被困住了。如果有人可以指出我正确的方向,甚至给我写一些代码片段,这将有助于我回到正轨,我将不胜感激。

我希望我发布的代码足够了。如果没有,只需发表评论,我将添加其他部分。

提前感谢您的时间!

1 个答案:

答案 0 :(得分:0)

我自己解决了这个问题,我想在这里发布代码以供将来参考。也许这不是最好的解决方案,但它对我有用。我在currentUser类的Loaded事件中添加了以下行:

DragDropDecorator

我无法编辑样式,因为它一旦设置就会被密封。所以我在新样式对象上使用了if (itemsControl.GetType() == typeof(TreeView)) { var originalStyle = itemsControl.Style; var newStyle = new Style(); newStyle.BasedOn = originalStyle; newStyle.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonDown))); newStyle.Setters.Add(new EventSetter(PreviewMouseMoveEvent, new MouseEventHandler(ItemsControl_PreviewMouseMove))); newStyle.Setters.Add(new EventSetter(PreviewMouseLeftButtonUpEvent, new MouseButtonEventHandler(ItemsControl_PreviewMouseLeftButtonUp))); newStyle.Setters.Add(new EventSetter(PreviewDropEvent, new DragEventHandler(ItemsControl_PreviewDrop))); newStyle.Setters.Add(new EventSetter(PreviewQueryContinueDragEvent, new QueryContinueDragEventHandler(ItemsControl_PreviewQueryContinueDrag))); newStyle.Setters.Add(new EventSetter(PreviewDragEnterEvent, new DragEventHandler(ItemsControl_PreviewDragEnter))); newStyle.Setters.Add(new EventSetter(PreviewDragOverEvent, new DragEventHandler(ItemsControl_PreviewDragOver))); newStyle.Setters.Add(new EventSetter(DragLeaveEvent, new DragEventHandler(ItemsControl_DragLeave))); itemsControl.ItemContainerStyle = newStyle; } 属性,以获取已设置的样式信息,添加BasedOn并将新样式应用于EventSetter