考虑第一版代码(MainWindow.xaml):
<ScrollViewer>
<local:CustomControl1 Width="1000" Height="1000" Background="Red"/>
</ScrollViewer>
其中CustomControl1派生自ItemsControl。在CustomControl1中,我重写了OnMouseDown事件。这段代码完美无缺,我确实抓住了鼠标按下事件。
现在第二版代码(MainWindow.xaml):
<local:CustomControl1 Width="1000" Height="1000" Background="Red"/>
在Generic.xaml中,我更改了我的项目控件的模板:
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
>
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
当我将scrollviewer作为控件模板的一部分时,我不再接收OnMouseDownEvent(左键单击)。出于某种原因,现在将鼠标按下事件标记为已处理。如果不是覆盖OnMouseDown,而是使用items控件构造函数中的以下语句,则会捕获该事件:
AddHandler(Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseDown), true);
首先,我想了解为什么将scrollviewer放在模板中改变鼠标的行为。第二,有没有人知道一些解决方法? 我提出的解决方案(通过捕获处理事件)对我来说是不可接受的。在我的应用程序中,只有当没有项控制子项处理它时,我才需要处理鼠标按下事件。
提前致谢。
答案 0 :(得分:23)
如果您查看Template
的默认ListBox
(也来自ItemsControl
),您会看到ScrollViewer
有{{1}在模板中设置。这允许鼠标事件传递到您的控件
Focusable="False"
答案 1 :(得分:0)
对于正在处理的事件,根本原因是当 ScrollViewer
可聚焦时,其内部 OnMouseLeftButtonDown
方法将尝试获取焦点,如果成功,则处理该事件.
这是来自 VS2019 反编译的代码:
public class ScrollViewer : ContentControl
{
...
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (Focus())
{
e.Handled = true;
}
base.OnMouseLeftButtonDown(e);
}
...
}
因此,一种方法是设置 Focusable="False"
(如 other answer 中所述),因为它可以防止这种情况发生。但这可能过于极端或限制性(对我而言)。例如,我发现阻止我的 ScrollViewer
接收焦点会 stop keybindings from being initiated。但如果它有重点,它们就会起作用。
所以另一种更灵活的方法是添加一个事件处理程序,如下所示:
<ScrollViewer
MouseLeftButtonDown="handler"
/>
handler
的作用所在:
void handler(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
e.Handled = false;
}
或者,如果您碰巧正在创建自己的派生 ScrollViewer,您可以只覆盖 OnMouseLeftButtonDown
。