为啥我的自定义控件不总是接收 MouseEnter 事件?
Posted
技术标签:
【中文标题】为啥我的自定义控件不总是接收 MouseEnter 事件?【英文标题】:Why are my custom controls not always receiving MouseEnter events?为什么我的自定义控件不总是接收 MouseEnter 事件? 【发布时间】:2019-05-21 06:04:16 【问题描述】:好的,我对 WPF 还很陌生,遇到了一个非常奇怪的问题。我的 XAML 的相关部分在 StackPanel 周围的 ScrollViewer 周围定义了一个边框,该边框使用 ItemsControl 填充,然后数据绑定到 CollectionViewSource,而 CollectionViewSource 又包装了标准的 ObservableCollection。 ItemsControl 定义了一个仅包含一个标记的 DataTemplate:我制作的一个自定义控件,称为 StackElement。我正在处理来自这个控件的三个事件——MouseEnter、MouseLeave 和 PreviewMouseLeftButtonUp。这些事件可以触发,但不可靠。
例如,在添加了一些新的 StackElement 之后,MouseEnter 事件通常不会在 first StackElement 上触发,直到我将鼠标悬停在其他几个 StackElement 上。一旦 MouseOver 成功触发一次,它就会继续在 StackElement 上正确触发。
但是,第一次将鼠标悬停在 StackElement 上并不总是失败。如果我从 beneath 接近 StackElements 并首先尝试最后一个,它总是会触发。当我这样做时,有时第一个会起作用,但第二个不会触发。曾经,他们俩都设法正确操作,但很少发生。
我没有对任何东西进行多线程处理,我的父控件都没有处理它们自己的事件,所有事件处理程序都仅包含用于调试目的的 WriteLine() 语句,并且 StackElement 代码隐藏也不处理任何事件。
我尝试将 ItemsControl 与 CollectionViewSource 解耦,以便将其直接绑定到 ObservableCollection,除了(如我所料)绕过我添加到 ViewSource 的排序功能外,什么也没做。除了使它们与 StackElement 中包含的其他控件相关联之外,我还尝试处理 StackElement 类本身中的事件。我尝试使用 DataTriggers,如果我记得它按预期工作的话,但我需要包含更高级的逻辑,例如多选和无法轻轻突出显示已选择的 StackElement。
对于上下文,我打算使用这些事件在用户将鼠标拖到 StackElements 上方时轻轻突出显示它们,并在按下鼠标时强烈突出显示它们 - 基本上,我需要看起来和感觉像 Windows 文件资源管理器的东西.据我所知,仅使用 DataTriggers 无法以优雅的方式完成。
这是我的事件处理程序(在 MainWindow.xaml 中):
private void StackElement_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
Console.WriteLine("OnPreviewMouseLeftButtonUp fired for a StackElement.");
private void StackElement_OnMouseEnter(object sender, MouseEventArgs e)
Console.WriteLine("OnMouseEnter fired for a StackElement.");
private void StackElement_OnMouseLeave(object sender, MouseEventArgs e)
Console.WriteLine("OnMouseLeave fired for a StackElement.");
这是我添加到绑定集合的方式(用于测试,这就是它连接到随机按钮的原因):
private void Btn_File_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
InitiativeStackElement t = new InitiativeStackElement(new Entity("TestName", 10, 11, 12, 13, null)); //InitiativeStackElement implements INotifyPropertyChanged so the databindings work
_entityProvider.Elements.Add(t); //_entityProvider is just a reference to a XAML-defined resource class, which is loaded up in the constructor so I don't have to call TryGetResource() whenever I want to use it. it's currently used for testing purposes only
最后,这是我的 XAML 中包含 StackElements 的部分:
<Border Grid.Row="1"
Margin="0,1,0,0"
Style="StaticResource StandardBorder">
<ScrollViewer Name="Scv_InitiativeStack">
<StackPanel Name="Stp_InitiativeStack">
<ItemsControl Name="Its_InitiativeStack" ItemsSource="Binding Source=StaticResource SortedInitiativeStack">
<ItemsControl.ItemTemplate>
<DataTemplate>
<con:StackElement Element="Binding" PreviewMouseLeftButtonUp="StackElement_OnPreviewMouseLeftButtonUp" MouseEnter="StackElement_OnMouseEnter" MouseLeave="StackElement_OnMouseLeave"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</Border>
StackElement 类只定义了一个 InitiativeStackElement 类型的 DependencyProperty。此对象的属性绑定到 StackElement 中的一些控件,这些控件始终正确显示。让我感到困惑的是事件的行为。
如前所述,我希望只要将鼠标拖到 StackElement 上,就会触发 MouseEnter 事件。但是,它只有在我满足不应影响其功能的看似随机的条件后才会触发,例如首先将鼠标悬停在另一个 StackElement 上。没有错误消息。
【问题讨论】:
“据我所知,仅使用 DataTriggers 无法以优雅的方式完成。” 为什么不呢? 因为我一直无法找到用于实现比“如果 A 和 B,设置属性”更高级的逻辑的 DataTrigger 示例。 正如您提到的,您只想突出显示...这可以在 XAML 中轻松完成 好吧,我不只是想在用户将鼠标悬停在某物上时突出显示。当用户单击我的 UserControl 时,我还想突出显示(以不同的颜色)。此外,当用户将鼠标悬停在已选择的元素上时,我不希望出现较浅的鼠标悬停突出显示颜色。我还打算添加多选功能,类似于 Windows 文件资源管理器中的 shift-click。我无法找到仅在 XAML 中完成所有这些操作的方法,因此我选择了事件。 我想说所有这些都是可能的标准功能。在我看来 ListView 是你真正需要的:docs.microsoft.com/en-us/dotnet/framework/wpf/controls/… 【参考方案1】:好的,我能够使用 ListBox 获得我想要的功能:
<Window.Resources>
<DataTemplate x:Key="InitiativeStackTemplate">
<con:StackElement Element="Binding"/>
</DataTemplate>
</Window.Resources>
<Border Margin="0,1,0,0"
Grid.Row="1"
Style="StaticResource StandardBorder">
<ScrollViewer Name="Scv_InitiativeStack">
<ListBox Name="Lbx_InitiativeStack"
SelectionMode="Extended"
ItemsSource="Binding Source=StaticResource SortedInitiativeStack"
ItemTemplate="StaticResource InitiativeStackTemplate"
HorizontalContentAlignment="Stretch"/>
</ScrollViewer>
</Border>
一切都按预期进行。
【讨论】:
以上是关于为啥我的自定义控件不总是接收 MouseEnter 事件?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 UISearchDisplayController 不使用我的自定义 tableViewCell?