当使用 ScrollViewer 作为某些控件模板的一部分时,将处理左键单击

发布于 2024-11-29 08:54:31 字数 1530 浏览 1 评论 0 原文

考虑代码的第一个版本 (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,而是在项目控件构造函数中使用以下语句,则会捕获该事件:

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

首先,我想了解为什么将scrollviewer 放置在模板中更改鼠标按下的行为。其次,有人知道一些解决方法吗? 我提出的解决方案(通过捕获已处理的事件)对我来说是不可接受的。在我的应用程序中,仅当没有项目控制子项处理鼠标按下事件时,我才需要处理鼠标按下事件。

提前致谢。

Consider first version of code (MainWindow.xaml):

<ScrollViewer>
    <local:CustomControl1 Width="1000" Height="1000" Background="Red"/>
</ScrollViewer>

where CustomControl1 derived from ItemsControl. Inside CustomControl1 , I overriding OnMouseDown event. This code works perfectly, and i do catch mouse down event.

Now second version of code (MainWindow.xaml):

<local:CustomControl1 Width="1000" Height="1000" Background="Red"/>

Inside Generic.xaml, I changing template of my items control:

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

When I putting scrollviewer as part of control template, I DO NOT receiving OnMouseDownEvent anymore (for left click). For some reason, now the mouse down event marked as handled. If instead of overriding OnMouseDown I using the following statement inside items control constructor, the event is catched:

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

First, I would like to understand why placing scrollviewer inside template changing behavior of mouse down. Second, does anyone know some workaround?
The solution I proposed (by catching handled events) is not acceptable for me. In my application, I need to handle mouse down events only if none of items control children handled it.

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

安穩 2024-12-06 08:54:31

例如,如果查看 ListBox 的默认 Template(它也派生自 ItemsControl),您将看到 ScrollViewer 在模板中设置了 Focusable="False"。这允许鼠标事件传递到您的控件

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

If you look at the default Template for a ListBox for example (which also derives from ItemsControl), you'll see that the ScrollViewer has Focusable="False" set in the Template. This allows the mouse events to pass through to your control

<ScrollViewer VerticalScrollBarVisibility="Visible"
              HorizontalScrollBarVisibility="Visible"
              Focusable="False" >
    <ItemsPresenter/>
</ScrollViewer>
似梦非梦 2024-12-06 08:54:31

至于正在处理的事件,根本原因是当 ScrollViewer 可聚焦时,其内部 OnMouseLeftButtonDown 方法将尝试获取焦点,如果成功,处理事件

这是 VS2019 反编译的代码:

public class ScrollViewer : ContentControl
{

    ...

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

        base.OnMouseLeftButtonDown(e);
    }

    ...

}

因此一种方法是设置 Focusable="False" (如 阻止启动键绑定。但如果它有重点,它们就会起作用。

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

<ScrollViewer
     MouseLeftButtonDown="handler"
     />

handler 的作用是:

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

或者,如果您碰巧要创建自己的派生 ScrollViewer,则只需重写 OnMouseLeftButtonDown 即可。

As regards the event being handled, a root cause is that when a ScrollViewer is focusable, its internal OnMouseLeftButtonDown method will try to get focus and if it succeeds, it handles the event.

Here's the very code from the VS2019 decompilation:

public class ScrollViewer : ContentControl
{

    ...

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

        base.OnMouseLeftButtonDown(e);
    }

    ...

}

So one method is to set Focusable="False" (as noted in the other answer) because it prevents this from occurring. But that might be too extreme or restrictive (it was for me). For example, I found that preventing my ScrollViewer from receiving focus would stop keybindings from being initiated. But if it had focus, they would work.

So another more flexible approach is to add an event handler like so:

<ScrollViewer
     MouseLeftButtonDown="handler"
     />

Where handler just does:

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

Or if you happen to be creating your own derived ScrollViewer you can just override OnMouseLeftButtonDown.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文