public interface IInputSignal { bool IsMatch(InputEventArgs args); } public class KeyDownSignal : KeySignal { public KeyDownSignal(Key key) : base(key) { } public override bool IsMatch(InputEventArgs args) { return Keyboard.IsKeyDown(Key); } } public class KeySignal : IInputSignal { public Key Key { get; set; } public KeySignal(Key key) { Key = key; } public virtual bool IsMatch(InputEventArgs args) { return args is KeyEventArgs e && e.Key == Key; } } public class KeyRepeatSignal : KeySignal { public KeyRepeatSignal(Key key) : base(key) { } public override bool IsMatch(InputEventArgs args) { return args is KeyEventArgs e && Key == e.Key && e.IsRepeat; } } public class MouseSignal : IInputSignal { public MouseButton MouseButton { get; set; } public MouseButtonState MouseButtonState { get; set; } public MouseSignal(MouseButton mouseButton, MouseButtonState state) { MouseButton = mouseButton; MouseButtonState = state; } public virtual bool IsMatch(InputEventArgs args) { MouseButtonEventArgs e = (MouseButtonEventArgs)args; return e != null && e.ChangedButton == MouseButton && e.ButtonState == MouseButtonState; } } public class MouseWheelSignal : IInputSignal { public bool IsMatch(InputEventArgs args) { MouseWheelEventArgs e = (MouseWheelEventArgs)args; return e != null; } } public class CommandMethod { public Action<CommandMethodEventArgs?>? Execute { get; set; } public Predicate<CommandMethodEventArgs?>? CanExecute { get; set; } public CommandMethod(Action<CommandMethodEventArgs?>? execute, Predicate<CommandMethodEventArgs?>? canExecute = null) { Execute = execute; CanExecute = canExecute; } } public class CommandMethodEventArgs : EventArgs { public bool Handled { get; set; } public object Data { get; set; } public InputCommand Command { get; set; } public CommandMethodEventArgs(object data, InputCommand command) { Data = data; Command = command; } } public enum MatchModel { Step, All } public class InputCommand : ICommand { int _index = 0; DateTime? _dateTime; public List<CommandMethod> CommandMethods { get; set; } public List<IInputSignal> InputSignals { get; set; } public string Name { get; set; } /// <summary> /// Step按顺序按,All所有信号同时存在 /// </summary> public MatchModel MatchModel { get; set; } public Window Owner { get; set; } public event EventHandler? CanExecuteChanged; public InputCommand(string name, IEnumerable<IInputSignal> inputSignals, MatchModel matchModel, Window owner) : this(name, inputSignals, matchModel, owner, null) { } public InputCommand(string name, IEnumerable<IInputSignal> inputSignals, MatchModel matchModel, Window owner, IEnumerable<CommandMethod>? commandMethods) { this.Name = name; MatchModel = matchModel; InputSignals = new List<IInputSignal>(); if (inputSignals != null) InputSignals.AddRange(inputSignals); CommandMethods = new List<CommandMethod>(); if (commandMethods != null) CommandMethods.AddRange(commandMethods); Owner = owner; if(Owner != null) Owner.CommandBindings.Add(new CommandBinding(this)); } /// <summary> /// MatchModel.All时args可以为null /// </summary> /// <param name="args"></param> /// <returns></returns> public virtual bool IsMatch(InputEventArgs args) { if (InputSignals == null || InputSignals.Count <= 0) return false; if (MatchModel == MatchModel.Step) { if (InputSignals[_index].IsMatch(args)) { if (_dateTime == null) { _dateTime = DateTime.Now; _index++; } else if ((DateTime.Now - _dateTime) <= TimeSpan.FromMilliseconds(200)) { _index++; _dateTime = DateTime.Now; } else { _index = 0; _dateTime = null; return false; } if (_index >= InputSignals.Count) { _index = 0; _dateTime = null; return true; } } } else { foreach (var k in InputSignals) if (!k.IsMatch(null)) return false; return true; } return false; } bool ICommand.CanExecute(object? parameter) { CommandMethodEventArgs arg = new CommandMethodEventArgs(parameter, this); return CanExecute(arg); } void ICommand.Execute(object? parameter) { CommandMethodEventArgs arg = new CommandMethodEventArgs(parameter, this); Execute(arg); } public bool CanExecute(CommandMethodEventArgs arg) { foreach (var method in CommandMethods) { if (method.CanExecute != null) { bool can = method.CanExecute.Invoke(arg); if (arg.Handled) return can; } } return true; } public void Execute(CommandMethodEventArgs arg) { foreach (var method in CommandMethods) { method.Execute?.Invoke(arg); if (arg.Handled) return; } } public void RaiseCmd() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } public static void TryExecute(Window window, InputEventArgs e) { foreach (CommandBinding cmd in window.CommandBindings) { if (cmd.Command is InputCommand command) { if (command.IsMatch(e)) { CommandMethodEventArgs arg = new CommandMethodEventArgs(e, command); command.Execute(arg); if (arg.Handled) break; } } } } public static void RegistPreview(Window window) { RegistPreviewKeyDown(window); RegistPreviewKeyUp(window); RegistPreviewMouseDown(window); RegistPreviewKeyUp(window); } public static void RegistPreviewKeyDown(Window window) { window.PreviewKeyDown += (s, e) => TryExecute(window, e); } public static void RegistPreviewKeyUp(Window window) { window.PreviewKeyUp += (s, e) => TryExecute(window, e); } public static void RegistPreviewMouseDown(Window window) { window.PreviewMouseDown += (s, e) => TryExecute(window, e); } public static void RegistPreviewMouseUp(Window window) { window.PreviewMouseUp += (s, e) => TryExecute(window, e); } public static void RegistPreviewMouseWheel(Window window) { window.PreviewMouseWheel += (s, e) => TryExecute(window, e); } }View Code
使用方式:
public class KeyBindingVM : ITemplateView { public ObservableCollection<InputCommand> InputCommands { get; set; } public string Title { get; set; } = "按键设置"; public List<IInputSignal> OldKeys { get; set; } public SimpleCommand<KeyEventArgs> AddKeyCmd { get; set; } public SimpleCommand<RoutedEventArgs> ClearKeyCmd { get; set; } public SimpleCommand SaveCmd { get; set; } public KeyBindingVM() { OldKeys = new List<IInputSignal>(); AddKeyCmd = new SimpleCommand<KeyEventArgs>(AddKey); ClearKeyCmd = new SimpleCommand<RoutedEventArgs>(ClearKey); SaveCmd = new SimpleCommand(() => { }); InputCommands = new ObservableCollection<InputCommand> { new InputCommand("背包", new KeyDownSignal[]{ new KeyDownSignal(Key.B) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }), new InputCommand("技能", new KeyDownSignal[]{ new KeyDownSignal(Key.K) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }), new InputCommand("任务", new KeyDownSignal[]{ new KeyDownSignal(Key.O) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }), new InputCommand("地图", new KeyDownSignal[]{ new KeyDownSignal(Key.M) }, MatchModel.All, App.Current.MainWindow, new List<CommandMethod>{ new CommandMethod(Alert) }), }; } void Alert(CommandMethodEventArgs? e) { MessageBox.Show(e.Command.Name); } private void ClearKey(RoutedEventArgs e) { var inputcmd = (e.OriginalSource as FrameworkElement).DataContext as InputCommand; OldKeys.Clear(); OldKeys.AddRange(inputcmd.InputSignals); inputcmd.InputSignals.Clear(); } private void AddKey(KeyEventArgs e) { e.Handled = true; if (e.IsRepeat) return; var control = (e.OriginalSource as TextBox); var inputcmd = control.DataContext as InputCommand; if (inputcmd.InputSignals.Exists(f => (f as KeySignal).Key == e.Key)) return; inputcmd.InputSignals.Add(new KeyDownSignal(e.Key)); control.SetBinding(TextBox.TextProperty, new Binding { Source = inputcmd, Path = new PropertyPath(nameof(inputcmd.InputSignals)), Converter = new Converters.KeyStringConverter() }); } } public class KeyStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return value; var keys = value as List<IInputSignal>; if (keys == null || keys.Count <= 0) return null; return string.Join("+", keys.Select(f => (f as KeySignal).Key)); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return Binding.DoNothing; } }View Code
<StackPanel> <ItemsControl ItemsSource="{Binding InputCommands}" VerticalAlignment="Top"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Columns="2"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate DataType="{x:Type input:InputCommand}"> <UniformGrid Columns="2"> <TextBlock Text="{Binding Name}"/> <TextBox Text="{Binding Path=InputSignals, Converter={StaticResource KeyStringConverter}}"> <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewKeyDown"> <i:InvokeCommandAction Command="{Binding DataContext.AddKeyCmd, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ItemsControl}}}" PassEventArgsToCommand="True"/> </i:EventTrigger> <i:EventTrigger EventName="PreviewMouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding DataContext.ClearKeyCmd, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ItemsControl}}}" PassEventArgsToCommand="True"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </UniformGrid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <Button Content="保存" Command="{Binding SaveCmd}"/> </StackPanel>View Code
标签:set,鼠标,get,快捷键,window,Key,new,WPF,public From: https://www.cnblogs.com/RedSky/p/18258955