Alt +鼠标滚轮缩放

时间:2018-03-29 07:15:52

标签: c# wpf

我有这段代码:

private void scrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.LeftAlt))
            {
                e.Handled = true;

                //initiate zoooom!
            }                    
        }  

我想实现alt +鼠标滚轮以便缩放,但我不想在滚动查看器上上/下丢失常规鼠标滚轮。我只是想在缩放时暂时禁用它。我已经尝试过对keyup和方法结束时的处理,但仍然没有运气。

上面的代码就像切换东西一样。 Alt + mousewheeling停止滚动查看器向上/向下滚动但在释放alt时滚动查看器仍然被锁定。它需要再次按下alt来释放它。

1 个答案:

答案 0 :(得分:2)

问题

您遇到的问题是在WPF应用程序中按 Alt 会导致内置行为将焦点从当前项移至Access Key Manager。要查看此行为,请按 Alt ,然后按空格,您将看到系统菜单弹出。

要更清楚地看到它,请在窗口中添加一个按钮,其内容在您希望成为您的角色之前具有下划线"访问键"

<Button Content="_Test"  />

然后按 Alt ,您会看到按钮文字更改为强调字母 T 。然后,如果按 T ,将按下该按钮。这是可操作性。

蛮力解决方案

修复代码的最简单,最快捷的方法是,每次按 Handled 时,只需将 Alt 键标记为 Handled ,即可禁用accessiblity通过窗口的 KeyDown 事件或 PreviewKeyDown 事件。

  

注意:这将禁用WPF窗口中的所有辅助功能,我不推荐它。

WPF窗口

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        KeyDown="Window_KeyDown"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ScrollViewer x:Name="ScrollViewer">
            <Border Background="Blue" Height="5000"></Border>
        </ScrollViewer>
    </Grid>
</Window>

代码背后

using System.Windows;
using System.Windows.Input;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.System && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)))
                e.Handled = true;
        }
    }
}

请注意,我们基本上会挂钩窗口的按键事件以捕获所有按键,然后我们会监听按键是否为系统键(可能包含F1,F2等功能键......),如果是这样的话他们检查是否按下了Alt键。

我们首先检查一下加速逻辑,不检查Alt键,除非我们先知道它是系统键。否则,您在整个键盘上按下的每个键(如在文本框中键入)都会导致检查两个Alt键并减慢速度。

智能解决方案

为了达到理想的效果,您真的需要能够检测到您的用户是否处于&#34;模式&#34;或者&#34;专注&#34;当用户开始按Alt时,他们处于您要禁用访问密钥的模式。

确定此模式的一种简单方法是仅在滚动查看器聚焦时禁用Alt。那么你的逻辑会改变,就像这样进行一次额外的检查。

private void Window_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.System && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)) 
        && e.OriginalSource == ScrollViewer) // <-- Added this check
        e.Handled = true;
}

然后,您将仅在视图具有焦点时禁用Alt(例如,已单击)。

如果您想要在 Alt 键之后检测模式(禁用Alt操作),您的挑战就会变得更难,例如在滚动开始后检测到它。这样做的原因是,只要按下 Alt ,就会启动访问键行为(按键时),以便在事实发生后更难以删除该行为。

可疑的解决方案

因此,在写完上述内容之后,我认为最好给你一个后alt风格检测的例子。所以这就是。这只是一个经过深思熟虑且经过测试的例子,很可能是错误的(主要是Task.Delay(0)依赖于在聚焦之前处理以前发布的系统密钥消息)但似乎工作正常。

现在您可以正常按 Alt ,然后按 Alt 然后开始滚动,发布后,访问键 defocused

WPF窗口

<Window x:Class="WpfApp1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                mc:Ignorable="d"
                KeyDown="Window_KeyDown"
                KeyUp="Window_KeyUp"
                Title="MainWindow" Height="450" Width="800">

    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="_File">
                <MenuItem Header="_Open"/>
                <MenuItem Header="_Close"/>
                <MenuItem Header="_Save"/>
            </MenuItem>
        </Menu>

        <ScrollViewer x:Name="ScrollViewer" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
            <Border Background="Blue" Height="5000"></Border>
        </ScrollViewer>
    </DockPanel>
</Window>

代码背后

using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace WpfApp1
{

    public partial class MainWindow : Window
    {
        private bool mHasScrolledWithSystemKeyDown = false;
        private bool mSystemKeyIsDown = false;
        private IInputElement mLastFocusedControl;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // If the system key is down...
            if (e.Key == Key.System)
                // Track it
                mSystemKeyIsDown = true;
        }

        private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            // If the system key is down while scrolling...
            if (mSystemKeyIsDown)
            {
                // If it is the first scroll since it being down...
                if (!mHasScrolledWithSystemKeyDown)
                    // Remember currently focused item
                    mLastFocusedControl = Keyboard.FocusedElement;

                // And flag as scrolled with system key down
                mHasScrolledWithSystemKeyDown = true;

                // Prevent scroll...
                e.Handled = true;

                // TODO: Zoom
            }
        }

        private void Window_KeyUp(object sender, KeyEventArgs e)
        {
            // On system key up...
            if (e.Key == Key.System)
            {
                // Track it
                mSystemKeyIsDown = false;

                // If we had scrolled with the system key down...
                if (mHasScrolledWithSystemKeyDown)
                    // Cause a small delay to allow this key up to process
                    Task.Delay(0).ContinueWith((t) => Dispatcher.Invoke(() =>
                    {
                        // Then focus the last control to "close" the system menu gracefully
                        mLastFocusedControl?.Focus();
                    }));

                // Flag the has scrolled to false to start again
                mHasScrolledWithSystemKeyDown = false;
            }
        }
    }
}

关闭时

请注意,如果您在按下Alt后尝试检测方法然后取消操作,请小心使用SendMessage之类的任何消息泵命令,只需发送 VM_KEYUP 命令不能作为按住时被物理按下的按钮,并且消息泵也有许多怪癖,你真的需要知道你在做什么不打破其他事情。 / p>