我怎样才能使WPF ScrollViewer成为单击鼠标中键? [英] How can I make WPF ScrollViewer middle-click-scroll?

查看:105
本文介绍了我怎样才能使WPF ScrollViewer成为单击鼠标中键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

单击鼠标中键(又名:鼠标滚轮),然后稍微向下移动鼠标,即可使用户在IE和大多数Windows应用程序中滚动.默认情况下,WPF控件中似乎缺少此行为吗?是否有设置,解决方法或明显的我缺少的东西?

Clicking the middle mouse button (aka: mouse wheel) and then moving the mouse down slightly lets users scroll in IE, and most Windows apps. This behavior appears to be missing in WPF controls by default? Is there a setting, a workaround, or something obvious that I'm missing?

推荐答案

我发现了如何使用3个鼠标事件(MouseDownMouseUpMouseMove)实现此目的.他们的处理程序附加到以下xaml中的ScrollViewer元素:

I have found how to achieve this using 3 mouse events (MouseDown, MouseUp, MouseMove). Their handlers are attached to the ScrollViewer element in the xaml below:

<Grid>
    <ScrollViewer MouseDown="ScrollViewer_MouseDown" MouseUp="ScrollViewer_MouseUp" MouseMove="ScrollViewer_MouseMove">
            <StackPanel x:Name="dynamicLongStackPanel">

            </StackPanel>
    </ScrollViewer>
    <Canvas x:Name="topLayer" IsHitTestVisible="False" />
</Grid>

最好在后台代码中编写行为而不是事件,但是并不是每个人都有必要的库,而且我也不知道如何将其与Canvas连接.

It would be better to write a behaviour instead of events in code-behind, but not everyone has the necessary library, and also I don't know how to connect it with the Canvas.

事件处理程序:

    private bool isMoving = false;                  //False - ignore mouse movements and don't scroll
    private bool isDeferredMovingStarted = false;   //True - Mouse down -> Mouse up without moving -> Move; False - Mouse down -> Move
    private Point? startPosition = null;
    private double slowdown = 200;                  //The number 200 is found from experiments, it should be corrected



    private void ScrollViewer_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (this.isMoving == true) //Moving with a released wheel and pressing a button
                this.CancelScrolling();
        else if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Pressed)
        {
            if (this.isMoving == false) //Pressing a wheel the first time
            {
                this.isMoving = true;
                this.startPosition = e.GetPosition(sender as IInputElement);
                this.isDeferredMovingStarted = true; //the default value is true until the opposite value is set

                this.AddScrollSign(e.GetPosition(this.topLayer).X, e.GetPosition(this.topLayer).Y);
            }
        }
    }

    private void ScrollViewer_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Released && this.isDeferredMovingStarted != true)
            this.CancelScrolling();
    }

    private void CancelScrolling()
    {
        this.isMoving = false;
        this.startPosition = null;
        this.isDeferredMovingStarted = false;
        this.RemoveScrollSign();
    }

    private void ScrollViewer_MouseMove(object sender, MouseEventArgs e)
    {
        var sv = sender as ScrollViewer;

        if (this.isMoving && sv != null)
        {
            this.isDeferredMovingStarted = false; //standard scrolling (Mouse down -> Move)

            var currentPosition = e.GetPosition(sv);
            var offset = currentPosition - startPosition.Value;
            offset.Y /= slowdown;
            offset.X /= slowdown;

            //if(Math.Abs(offset.Y) > 25.0/slowdown)  //Some kind of a dead space, uncomment if it is neccessary
            sv.ScrollToVerticalOffset(sv.VerticalOffset + offset.Y);
            sv.ScrollToHorizontalOffset(sv.HorizontalOffset + offset.X);
        }
    }

如果要删除方法调用AddScrollSignRemoveScrollSign,此示例将起作用.但是我用设置滚动图标的2种方法扩展了它:

If to remove the method calls AddScrollSign and RemoveScrollSign this example will work. But I have extended it with 2 methods which set scroll icon:

    private void AddScrollSign(double x, double y)
    {
        int size = 50;
        var img = new BitmapImage(new Uri(@"d:\middle_button_scroll.png"));
        var adorner = new Image() { Source = img, Width = size, Height = size };
        //var adorner = new Ellipse { Stroke = Brushes.Red, StrokeThickness = 2.0, Width = 20, Height = 20 };

        this.topLayer.Children.Add(adorner);
        Canvas.SetLeft(adorner, x - size / 2);
        Canvas.SetTop(adorner, y - size / 2);
    }

    private void RemoveScrollSign()
    {
        this.topLayer.Children.Clear();
    }

图标示例:

最后一句话:Press -> Immediately Release -> Move的方式存在一些问题.如果用户单击鼠标左键或键盘上的任意键,或者应用程序失去焦点,则应该取消滚动.有很多事件,我没有时间处理所有事件.

And one last remark: there are some problems with the way Press -> Immediately Release -> Move. It is supposed to cancel scrolling if a user clicks the mouse left button, or any key of keyboard, or the application looses focus. There are many events and I don't have time to handle them all.

但是标准方式Press -> Move -> Release可以正常工作.

But standard way Press -> Move -> Release works without problems.

这篇关于我怎样才能使WPF ScrollViewer成为单击鼠标中键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆