none
MVVM模式下,键盘事件怎么被Command绑定?以及如何在Command绑定的ViewModel对象内的方法中获取用户按下的键的字符串编号? RRS feed

  • 问题

  • MVVM模式下,用户键盘事件怎么被Command绑定?以及如何在Command绑定的ViewMOdel对象内的方法中获取用户按下的键所映射的字符串编号?
    2017年5月26日 1:18

答案

  • HI,

    >>MVVM模式下,用户键盘事件怎么被Command绑定?

    <Window x:Class="wpfLearning.wpfCommanding.CommandWithInputBindingsSample"
            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"
            xmlns:local="clr-namespace:wpfLearning.wpfCommanding"
            mc:Ignorable="d"
            Title="CommandWithInputBindingsSample" Height="300" Width="300">
        
        <Window.InputBindings>
                <KeyBinding x:Name="keybind" Command="{Binding SomeCommand}" Key="Q" Modifiers="Ctrl"/>
         </Window.InputBindings>
    
        <StackPanel>
            <Button Command="{Binding SomeCommand}" >open</Button>
        </StackPanel>  
    </Window>
     public partial class CommandWithInputBindingsSample : Window
        {
            public CommandWithInputBindingsSample()
            {
                InitializeComponent();
                MyViewModel vm = new MyViewModel();
                this.DataContext = vm;
            }
        }  
    public class MyViewModel
        {
            private ICommand someCommand;
            public ICommand SomeCommand
            {
                get
                {
                    return someCommand
                        ?? (someCommand = new ActionCommand(() =>
                        {
                            MessageBox.Show("SomeCommand");
                        }));
                }
            }
        }
    


        public class ActionCommand : ICommand
        {
            private readonly Action _action;
    
            public event EventHandler CanExecuteChanged;
    
            public ActionCommand(Action action)
            {
                _action = action;
            }
    
            public void Execute(object parameter)
            {
                _action();
            }
    
            public bool CanExecute(object parameter)
            {
                return true;
            }
        }

    当然你也可以使用C#代码来设置热键。

       someCommand.InputGestures.Add(new KeyGesture(Key.Q, ModifierKeys.Alt));

    >>以及如何在Command绑定的ViewMOdel对象内的方法中获取用户按下的键所映射的字符串编号?

    用户按下的键所映射的字符串编号是指什么?你的意思是指按键的Key吗?还是其他?请详细描述一下。

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    2017年5月26日 8:45
    版主
  • Hi,

    >>有一个问题,如果有两个控件,都需要同样的一个键,来处理。怎样判断是谁要接受处理呢?例如设置delete键,TextBox的文字清除或对ListBox的选中项进行移除,需要用到delete键,怎样判定究竟是TextBox要接受处理,还是ListBox?这得获得焦点啊,并判断焦点是不是ListView还是TextBox,还是在ViewModel对象中判断,ViewModel对象得知道哪个控件获得焦点把。

    你可以在执行方法中处理你的逻辑。满足一定条件采取执行。

      private void cb_Execute(object sender, ExecutedRoutedEventArgs e)
            {
                if (txtBox.IsFocused)
                {
                    txtBox.Clear();
                }
                if (listBox.IsFocused)
                {
                    if(listBox.SelectedItem!=null)
                   listBox.Items.Remove(listBox.SelectedItem);
                }
                e.Handled = true;
            }

    如果你不为命令源(ICommandSource)指定其命令对象(CommandTarget),那么其将会把界面上获得键盘焦点的元素作为默认的命令对象,比如界面上有两个文本框,不必担心主菜单项上的“粘贴”操作是针对哪个文本框的,谁获得焦点便针对谁,这符合大家的习惯。

     <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <StackPanel HorizontalAlignment="Center" Grid.Row="0" Orientation="Horizontal">
                <Menu Width="Auto" Height="20" DockPanel.Dock="Top">
                    <MenuItem Command="ApplicationCommands.Copy" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Paste" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Cut" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Redo" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Undo" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                </Menu>
            </StackPanel>
            <StackPanel  Grid.Row="1">
                <TextBox Height="100" Background="AliceBlue"></TextBox>
                <TextBox Height="100" Background="AntiqueWhite"></TextBox>
            </StackPanel>
        </Grid>

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2017年5月29日 5:31
    版主

全部回复

  • HI,

    >>MVVM模式下,用户键盘事件怎么被Command绑定?

    <Window x:Class="wpfLearning.wpfCommanding.CommandWithInputBindingsSample"
            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"
            xmlns:local="clr-namespace:wpfLearning.wpfCommanding"
            mc:Ignorable="d"
            Title="CommandWithInputBindingsSample" Height="300" Width="300">
        
        <Window.InputBindings>
                <KeyBinding x:Name="keybind" Command="{Binding SomeCommand}" Key="Q" Modifiers="Ctrl"/>
         </Window.InputBindings>
    
        <StackPanel>
            <Button Command="{Binding SomeCommand}" >open</Button>
        </StackPanel>  
    </Window>
     public partial class CommandWithInputBindingsSample : Window
        {
            public CommandWithInputBindingsSample()
            {
                InitializeComponent();
                MyViewModel vm = new MyViewModel();
                this.DataContext = vm;
            }
        }  
    public class MyViewModel
        {
            private ICommand someCommand;
            public ICommand SomeCommand
            {
                get
                {
                    return someCommand
                        ?? (someCommand = new ActionCommand(() =>
                        {
                            MessageBox.Show("SomeCommand");
                        }));
                }
            }
        }
    


        public class ActionCommand : ICommand
        {
            private readonly Action _action;
    
            public event EventHandler CanExecuteChanged;
    
            public ActionCommand(Action action)
            {
                _action = action;
            }
    
            public void Execute(object parameter)
            {
                _action();
            }
    
            public bool CanExecute(object parameter)
            {
                return true;
            }
        }

    当然你也可以使用C#代码来设置热键。

       someCommand.InputGestures.Add(new KeyGesture(Key.Q, ModifierKeys.Alt));

    >>以及如何在Command绑定的ViewMOdel对象内的方法中获取用户按下的键所映射的字符串编号?

    用户按下的键所映射的字符串编号是指什么?你的意思是指按键的Key吗?还是其他?请详细描述一下。

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    2017年5月26日 8:45
    版主
  • HI,

    >>MVVM模式下,用户键盘事件怎么被Command绑定?

    <Window x:Class="wpfLearning.wpfCommanding.CommandWithInputBindingsSample"
            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"
            xmlns:local="clr-namespace:wpfLearning.wpfCommanding"
            mc:Ignorable="d"
            Title="CommandWithInputBindingsSample" Height="300" Width="300">
        
        <Window.InputBindings>
                <KeyBinding x:Name="keybind" Command="{Binding SomeCommand}" Key="Q" Modifiers="Ctrl"/>
         </Window.InputBindings>
    
        <StackPanel>
            <Button Command="{Binding SomeCommand}" >open</Button>
        </StackPanel>  
    </Window>
     public partial class CommandWithInputBindingsSample : Window
        {
            public CommandWithInputBindingsSample()
            {
                InitializeComponent();
                MyViewModel vm = new MyViewModel();
                this.DataContext = vm;
            }
        }  
    public class MyViewModel
        {
            private ICommand someCommand;
            public ICommand SomeCommand
            {
                get
                {
                    return someCommand
                        ?? (someCommand = new ActionCommand(() =>
                        {
                            MessageBox.Show("SomeCommand");
                        }));
                }
            }
        }


        public class ActionCommand : ICommand
        {
            private readonly Action _action;
    
            public event EventHandler CanExecuteChanged;
    
            public ActionCommand(Action action)
            {
                _action = action;
            }
    
            public void Execute(object parameter)
            {
                _action();
            }
    
            public bool CanExecute(object parameter)
            {
                return true;
            }
        }

    当然你也可以使用C#代码来设置热键。

       someCommand.InputGestures.Add(new KeyGesture(Key.Q, ModifierKeys.Alt));

    >>以及如何在Command绑定的ViewMOdel对象内的方法中获取用户按下的键所映射的字符串编号?

    用户按下的键所映射的字符串编号是指什么?你的意思是指按键的Key吗?还是其他?请详细描述一下。

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    有一个问题,如果有两个控件,都需要同样的一个键,来处理。怎样判断是谁要接受处理呢?

    例如设置delete键,TextBox的文字清除或对ListBox的选中项进行移除,需要用到delete键,怎样判定究竟是TextBox要接受处理,还是ListBox?这得获得焦点啊,并判断焦点是不是ListView还是TextBox,还是在ViewModel对象中判断,ViewModel对象得知道哪个控件获得焦点把。

    要怎么做呢





    2017年5月26日 12:14
  • Hi 便携式家园,

    我这里有一个解决方案

    设置CommandParameter来区分到底是哪一个控件执行了这个Command。

    给你一个简单列子:

    XAML:

    <Button x:Name="button" Content="Delete" CommandParameter={Binding ElementName=button} Command="{Binding DeleteCommand}"/>

    <RadioButton x:Name="radioA" Content="A" CommandParameter={Binding ElementName=radioA} Command="{Binding DeleteCommand}"/>

    <RadioButton x:Name="radioB" Content="B" CommandParameter={Binding ElementName=radioA} Command="{Binding DeleteCommand}"/>

    CS:

    public class ActionCommand : ICommand

    {

    ...

           

    public void Execute(object parameter)

    {

    Type target = parameter.GetType();

    switch(target.Name)

    {

    case "Button":

    excuteButtonDeleteAction();

    break;

    case "RadioButton":

    swith((parameter as RadioButton))

    {

    case "A":

    excuteRadioADeleteAction();

    break;

    case "B":

    excuteRadioBDeleteAction();

    break;

    }

    break;

    }

    }

    ...

    }

    以上只是一个大致思路,你可以根据你的实际需要修改和补充。

    Best wishes,
    Lee

                          
    2017年5月27日 2:36
  • Hi,

    >>有一个问题,如果有两个控件,都需要同样的一个键,来处理。怎样判断是谁要接受处理呢?例如设置delete键,TextBox的文字清除或对ListBox的选中项进行移除,需要用到delete键,怎样判定究竟是TextBox要接受处理,还是ListBox?这得获得焦点啊,并判断焦点是不是ListView还是TextBox,还是在ViewModel对象中判断,ViewModel对象得知道哪个控件获得焦点把。

    你可以在执行方法中处理你的逻辑。满足一定条件采取执行。

      private void cb_Execute(object sender, ExecutedRoutedEventArgs e)
            {
                if (txtBox.IsFocused)
                {
                    txtBox.Clear();
                }
                if (listBox.IsFocused)
                {
                    if(listBox.SelectedItem!=null)
                   listBox.Items.Remove(listBox.SelectedItem);
                }
                e.Handled = true;
            }

    如果你不为命令源(ICommandSource)指定其命令对象(CommandTarget),那么其将会把界面上获得键盘焦点的元素作为默认的命令对象,比如界面上有两个文本框,不必担心主菜单项上的“粘贴”操作是针对哪个文本框的,谁获得焦点便针对谁,这符合大家的习惯。

     <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <StackPanel HorizontalAlignment="Center" Grid.Row="0" Orientation="Horizontal">
                <Menu Width="Auto" Height="20" DockPanel.Dock="Top">
                    <MenuItem Command="ApplicationCommands.Copy" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Paste" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Cut" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Redo" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                    <MenuItem Command="ApplicationCommands.Undo" Header="{Binding Path=Command.Text, RelativeSource={RelativeSource Self}}"/>
                </Menu>
            </StackPanel>
            <StackPanel  Grid.Row="1">
                <TextBox Height="100" Background="AliceBlue"></TextBox>
                <TextBox Height="100" Background="AntiqueWhite"></TextBox>
            </StackPanel>
        </Grid>

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2017年5月29日 5:31
    版主