开发者

When using ScrollViewer as part of template for some control, the left click is handled

开发者 https://www.devze.com 2023-03-28 04:12 出处:网络
Consider first version of code (MainWindow.xaml): <ScrollViewer> <local:CustomControl1 Width=\"1000\" Height=\"1000\" Background=\"Red\"/>

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}"
                 开发者_如何学C       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.


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>


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号