当将ScrollViewer作为某个控件的模板的一部分时,左键单击会被处理。

14

首先考虑代码的第一个版本(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>

当我将滚动条作为控件模板的一部分时,我不再收到OnMouseDownEvent事件(左键点击)。由于某种原因,现在鼠标按下事件被标记为已处理。如果不是通过覆盖OnMouseDown方法,而是在项控件构造函数中使用以下语句,则可以捕获事件:

AddHandler(Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseDown), true);

首先,我想了解为什么在模板中放置scrollviewer会改变鼠标按下的行为。其次,有谁知道一些解决方法吗?

我提出的解决方案(通过捕捉已处理事件)对我来说不可接受。在我的应用程序中,只有在没有任何项目控件子级处理它时,我才需要处理鼠标按下事件。

先行致谢。

2个回答

29

例如,如果您查看默认的ListBox Template(它也派生自ItemsControl),您会看到ScrollViewer在模板中具有Focusable="False"设置。这使得鼠标事件可以传递到您的控件。

<ScrollViewer VerticalScrollBarVisibility="Visible"
              HorizontalScrollBarVisibility="Visible"
              Focusable="False" >
    <ItemsPresenter/>
</ScrollViewer>

我不明白。focusable = false 究竟如何影响事件处理? - James Joshua Street

0
关于正在处理的事件,根本原因是当一个可以获得焦点的ScrollViewer,其内部的OnMouseLeftButtonDown方法将尝试获取焦点,如果成功,则处理该事件

这是来自VS2019反编译的代码:

public class ScrollViewer : ContentControl
{

    ...

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        if (Focus())
        {
            e.Handled = true;
        }

        base.OnMouseLeftButtonDown(e);
    }

    ...

}

因此,一种方法是设置Focusable="False"(如其他答案中所述),因为它可以防止这种情况发生。但这可能过于极端或限制性(对我来说是这样)。例如,我发现防止我的ScrollViewer获得焦点会停止启动键绑定。但如果它有焦点,它们将起作用。

因此,另一种更灵活的方法是添加事件处理程序,如下所示:

<ScrollViewer
     MouseLeftButtonDown="handler"
     />

其中handler只是执行以下操作:

void handler(MouseButtonEventArgs e)
{
    base.OnMouseLeftButtonDown(e);
    e.Handled = false;
}

或者如果您正在创建自己的派生 ScrollViewer,则可以直接覆盖 OnMouseLeftButtonDown


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接