首页 > 其他分享 >WPF支持任意快捷键+鼠标组合的绑定类

WPF支持任意快捷键+鼠标组合的绑定类

时间:2024-06-20 16:44:41浏览次数:12  
标签:set 鼠标 get 快捷键 window Key new WPF public

    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

相关文章

  • 演示:WPF开发的Diagram自动化流程图应用
    一、目的:演示Diaram应用功能二、预览三、功能列表功能模块通用测试流程图仪器仪表机器人网络通信测试PLC测试轮毂生产线流程测试 图像处理目标检测绘图思维导图图表流程图功能模板管理工程管理模块许可管理工具栏开始停止删除清......
  • DevExpress WPF中文教程:Grid - 如何将更改发布到数据库(设计时)?
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。无论是Office办公软件的衍伸产品,还是以数据为中心......
  • WPF/C#:在DataGrid中显示选择框
    前言在使用WPF的过程中可能会经常遇到在DataGrid的最前或者最后添加一列选择框的需求,今天跟大家分享一下,在自己的项目中是如何实现的。整体实现效果如下:如果对此感兴趣,可以接下来看具体实现部分。实践假设数据库中的模型如下:publicclassPerson{publicintId......
  • 【C#】WPF 使用Storyboard故事板做动画效果
    <Stylex:Key="ButtonAnimationBlueStyle"BasedOn="{x:Null}"TargetType="{x:TypeButton}"><SetterProperty="Template"><Setter.Value><ControlTem......
  • WPF/C#:显示分组数据的两种方式
    前言本文介绍自己在遇到WPF对数据进行分组显示的需求时,可以选择的两种方案。一种方案基于ICollectionView,另一种方案基于IGrouping。基于ICollectionView实现相关cs代码:[ObservableProperty]privateObservableCollection<People>people;publicGroupDemoViewModel(){......
  • react 自定义鼠标右键点击事件
    功能:鼠标右键点击节点时,出现“复制”功能,点击其他部位,隐藏“复制”;鼠标右键事件的文案,始终在鼠标点击位置的右下方;点击复制,提示复制成功效果图:代码:const[showRight,setShowRight]=useState(false);constcontextMenu=useRef(null);const[clickX,setClickX]=us......
  • Vue3鼠标悬浮个人头像时出现修改头像,点击出现弹框,上传头像使用cropperjs可裁剪预览
    实现效果:鼠标悬浮到头像上,下方出现修改头像点击修改头像出现弹框,弹框中可上传头像,并支持头像的裁剪及预览 实现方式: 1.tempalte中<divclass="img-box"> <imgv-if="avatarImgUrl":src="avatarImgUrl"class="avatar"/> <divclass="text"@......
  • Qt 应用程序中自定义鼠标光标
    在Qt应用程序中,你可以自定义鼠标光标。你可以使用`QCursor`类来设置不同类型的鼠标光标,比如内置样式或者自定义的图片。以下是一些使用示例:使用内置光标样式Qt提供了一些内置的光标样式,你可以使用这些样式来改变光标的外观,例如箭头、手形、等待图标等等。1#include<QA......
  • 树莓派pico入坑笔记,快捷键键盘制作
    使用usb_hid功能制作快捷键小键盘,定义了6个键,分别是ctrl+z ctrl+v ctrl+c ctrl+a ctrl+w ctrl+n 对应引脚board.GP4,board.GP8,board.GP13board.GP28,board.GP20,board.GP17需要用到的库,记得复制进单片机存储里面然后是main主程序代码importboardfromdig......
  • 一行代码实现鼠标横向滚动
    ......