我有这段代码:
private void scrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftAlt))
{
e.Handled = true;
//initiate zoooom!
}
}
我想实现alt +鼠标滚轮以便缩放,但我不想在滚动查看器上上/下丢失常规鼠标滚轮。我只是想在缩放时暂时禁用它。我已经尝试过对keyup和方法结束时的处理,但仍然没有运气。
上面的代码就像切换东西一样。 Alt + mousewheeling停止滚动查看器向上/向下滚动但在释放alt时滚动查看器仍然被锁定。它需要再次按下alt来释放它。
答案 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 对于Alt的强大>命令不能作为按住时被物理按下的按钮,并且消息泵也有许多怪癖,你真的需要知道你在做什么不打破其他事情。 / p>