更新:因此,我有解决我眼前问题的方法。我没有成功开设“我自己的” TreeView
课程。但是,我要这样做的原因是因为基于ButtonBase
的控件无法在Popup
的{{1}}中起作用,并且在@MarkFeldman的帮助下,我发现了一个从另一个角度来看的解决方案。
问题在于TreeView
和MouseDown
事件冒泡,冒泡越过MouseUp
及其所有者之间的逻辑树边界。因此,当您单击Popup
内托管的内容时,最终拥有Popup
的{{1}}和TreeViewItem
会听到有关它的信息。然后,这会触发TreeView
内部的代码,该代码检查“我有焦点吗?”,如果没有,有帮助地将焦点重新设置为自身,但作为单独的逻辑树,{ {1}}有其自己的焦点上下文,因此在处理点击的过程中,此{em}会从Popup
控件有效地窃取焦点。 TreeView
通过忽略点击来对此做出响应。
Popup
中的这种错误处理仅在Button
和Button
事件到达时发生。如果有办法阻止它首先看到这些事件,该怎么办?好吧,如果您拦截TreeView
和MouseDown
事件并将其标记为MouseUp
,则框架不会生成 PreviewMouseDown
和{{1 }}事件开始。
看参考源,似乎PreviewMouseUp
的点击处理被捆绑在两个Handled
方法中:
https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,414 https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,478
这意味着您可以从自己的子类中调用它们!因此,除了使“我自己的” MouseDown
在所有控件正常工作的情况下,我还可以使“我自己的” MouseUp
在ButtonBase
的{{1}}中正常工作。由于所有直接的实际点击处理都可以直接访问,并且它的事件通常响应为使用与protected
事件相同的TreeView
类型,并且默认情况下处理将事件标记为CheckBox
,整个实现归结为:
Popup
很好!
原始问题:
我需要克隆TreeView
WPF类-用我自己的代码运行的控件的副本。 (该控件中存在一个错误,Microsoft似乎并不认为它具有足够高的优先级,因此,它完全不可能在{{1所显示的弹出窗口中)托管按钮(包括复选框和单选按钮)。 }} s。link)
Microsoft在实施基本WPF控件方面投入了大量EventArgs
恶作剧,给我带来了严重的困难。我遇到的几个问题:
控件具有属性Preview
,该属性使它们可以接管Handled
的基本滚动处理。但是,它被标记为public class CheckBoxThatWorks : CheckBox
{
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) => base.OnMouseLeftButtonDown(e);
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) => base.OnMouseLeftButtonUp(e);
}
,这使我似乎无法拥有自己的控件来进行键盘输入的滚动处理。我打算尝试让TreeView
而不是TreeViewItem
的{{1}}处理键盘滚动,以防止它拦截的键引发internal
事件。我还不了解这可能会有什么警告。
Visual States系统允许您声明输入不同状态时应应用的样式,但实际上输入状态似乎与HandlesScrolling
的虚拟方法ScrollViewer
捆绑在一起类型。所有想要在视觉状态之间切换的控件都可以重写此方法,并检查其状态以确定应显示哪个视觉状态。等一下。他们不能因为方法是internal
!显然只有Microsoft才能创建设置自己的视觉状态的控件?
我是否可以使用任何策略来解决这些局限性,还是我完全不走运?