WPF MVVM如何在运行时从用户分配键盘快捷键

时间:2018-12-17 13:56:06

标签: c# wpf xaml mvvm

正如标题所述,我正在寻找一种使用WPF MVVM模式在运行时从用户分配键盘快捷键的方法。我知道我可以像这样在开始时定义键盘快捷键:

<Window.InputBindings>
    <KeyBinding Command="{Binding MyCommand}" Key="A"/>
</Window.InputBindings>

我还看到有一种方法可以parse input bindings from a user。但是,我正在努力将ViewModel的inputbinding绑定到MainWindow的InputBinding。我不知道该如何实现。这是我的MainWindow中的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel();
    }
}

这是我的ViewModel中的一些示例代码:

public partial class MainWindowViewModel : Window, INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        KeyBinding kb = new KeyBinding { Key = Key.T, Command = MyCommand };
        this.InputBindings.Add(kb);
    }
}

我知道this.InputBindings.Add(kb);部分应该用其他东西代替;而是将键绑定添加到MainWindow的InputBinding中。但是,我不知道如何使用MVVM模式执行此操作。因此:我将如何去做?

2 个答案:

答案 0 :(得分:1)

您可能在视图模型中定义了输入绑定,但是仍然需要以某种方式将它们添加到视图中。

例如,您可以使用为您执行此操作的附加行为:

public class InputBindingsBehavior
{
    public static readonly DependencyProperty InputBindingsProperty = DependencyProperty.RegisterAttached(
        "InputBindings", typeof(IEnumerable<InputBinding>), typeof(InputBindingsBehavior), new PropertyMetadata(null, new PropertyChangedCallback(Callback)));

    public static void SetInputBindings(UIElement element, IEnumerable<InputBinding> value)
    {
        element.SetValue(InputBindingsProperty, value);
    }
    public static IEnumerable<InputBinding> GetInputBindings(UIElement element)
    {
        return (IEnumerable<InputBinding>)element.GetValue(InputBindingsProperty);
    }

    private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        UIElement uiElement = (UIElement)d;
        uiElement.InputBindings.Clear();
        IEnumerable<InputBinding> inputBindings = e.NewValue as IEnumerable<InputBinding>;
        if (inputBindings != null)
        {
            foreach (InputBinding inputBinding in inputBindings)
                uiElement.InputBindings.Add(inputBinding);
        }
    }
}

查看模型:

public partial class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        KeyBinding kb = new KeyBinding { Key = Key.T, Command = MyCommand };
        InputBindings.Add(kb);
    }

    public List<InputBinding> InputBindings { get; } = new List<InputBinding>();

    public ICommand MyCommand => ...
}

查看:

<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"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="Window18" Height="300" Width="300"
        local:InputBindingsBehavior.InputBindings="{Binding InputBindings}">
    <Grid>

    </Grid>
</Window>

答案 1 :(得分:0)

如果这些要保留下来以便下次用户运行该应用程序时它们可以工作,那么您可以考虑将资源字典创建为字符串或未编译的平面文件。

这将允许您将xaml作为字符串使用。您可以将其写入磁盘,然后将xamlreader.load写入资源字典,然后将其合并到应用程序资源中。

https://social.technet.microsoft.com/wiki/contents/articles/28797.wpf-dynamic-xaml.aspx

这种方法有几个好处:

样式很容易持久。 您可以尝试一下,看看发生了什么。 您可以使用从viewmodel调用的模型方法将文件写入磁盘。