使用ScrollViewer作为模板的一部分进行某些控制时,会处理左键单击

时间:2011-08-14 04:52:45

标签: wpf controltemplate scrollviewer

考虑第一版代码(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放在模板中改变鼠标的行为。第二,有没有人知道一些解决方法? 我提出的解决方案(通过捕获处理事件)对我来说是不可接受的。在我的应用程序中,只有当没有项控制子项处理它时,我才需要处理鼠标按下事件。

提前致谢。

2 个答案:

答案 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