我对 WPF 还很陌生,所以最好描述一下其意图:
主窗口内有多个用户控件。每个用户控件都有自己的按钮,我想使用键盘快捷键将其绑定到命令。
MainWindow.xaml
是这样的:
<Window ...>
<Window.DataContext>
<viewModel:MainViewModel/>
</Window.DataContext>
...
<ContentControl Grid.Column="1"
Margin="5"
Content="{Binding HomeToolbarView}"/>
...
</Window>
如您所见,我在代码隐藏中使用了一些虚拟机绑定。在
app.xaml
:
<Application ...>
<Application.Resources>
<ResourceDictionary>
...
<DataTemplate DataType="{x:Type viewModel:HomeToolbarViewModel}">
<view:HomeToolbar/>
</DataTemplate>
...
</ResourceDictionary>
</Application.Resources>
</Application>
我将
HomeToolbar
绑定到它的 HomeToolbarViewModel
并在 MainViewModel
:
public class MainViewModel : ObservableObject {
// This is bound to the XAML
private object homeToolbarView;
...
public HomeToolbarViewModel HomeToolbarVM { get; set; }
...
public object HomeToolbarView
{
get { return homeToolbarView; }
set
{
homeToolbarView = value;
OnPropertyChanged();
}
}
...
public MainViewModel() {
...
HomeToolbarVM = new HomeToolbarViewModel();
homeToolbarView = HomeToolbarVM;
...
}
}
最后
HomeToolbar.xaml
:
<UserControl xmlns:self="clr-namespace:ChordTuner.MVVM.ViewModels"
...>
<UserControl.CommandBindings>
<!-- Error: Compiler binds this to the DataContext of the view, i.e. HomeToolbar.xaml.cs, and not to the real DataContext, i.e. the HomeToolbarViewModel!
<CommandBinding Command="self:HomeToolbarCommands.NewCommand" Executed="{Binding NewCommand_Executed}" .../> />
</UserControl.CommandBindings>
<!-- Only to simplify -->
<StackPanel>
<Button Command="self:HomeToolbarCommands.NewCommand" />
<!-- No error, the command is correctly bound to the DataContext, i.e. the VM! -->
<Button Command={Binding ARelayCommandProp}"/>
</StackPanel>
</UserControl>
与
HomeToolbarViewModel.cs
:
namespace ChordTuner.MVVM.ViewModels {
public class HomeToolbarViewModel : ObservableObject {
...
private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("New from XAML");
}
...
}
public static class HomeToolbarCommands
{
public static readonly RoutedUICommand NewCommand = new RoutedUICommand
(
"New1",
"New2",
typeof(HomeToolbarCommands),
new InputGestureCollection()
{
new KeyGesture(Key.N, ModifierKeys.Control)
}
);}
}
Visual Studio 输出以下错误:
CS1061“HomeToolbar”不包含“NewCommand_Executed”的定义,并且找不到接受“HomeToolbar”类型的第一个参数的可访问扩展方法“NewCommand_Executed”(您是否缺少 using 指令或程序集引用?)ChordTuner
令我感到奇怪的是,使用
RelayCommand
类的按钮正确绑定到视图模型(如 app.xaml
中所示),但 CommandBindings
却没有。
所有这一切的目标是为所有用户控制按钮分配全局快捷键。使用
InputBindings
强制用户控件处于焦点状态。但我有多个用户控件需要响应不同的命令/快捷方式,无论焦点如何。
更新 这是
HomeToolbarView
构造函数
public HomeToolbar()
{
InitializeComponent();
for (int index = 0; index < MidiIn.NumberOfDevices; index++)
{
midiInComboBox.Items.Add(MidiIn.DeviceInfo(index).ProductName);
}
for (int index = 0; index < MidiOut.NumberOfDevices; index++)
{
midiOutComboBox.Items.Add(MidiOut.DeviceInfo(index).ProductName);
}
// This event is called when DataContext is changed. This happens because we binded the HomeToolbarViewModel inside the app.xaml.
DataContextChanged += new DependencyPropertyChangedEventHandler(HomeToolbar_DataContextChanged);
}
...
void HomeToolbar_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
viewModel = (HomeToolbarViewModel?)DataContext;
if (viewModel == null) return;
if (MidiOut.NumberOfDevices > 0)
{
viewModel.SelectedMidiOutIndex = 0;
}
if (MidiIn.NumberOfDevices > 0)
{
viewModel.SelectedMidiInIndex = 0;
}
}
有人解释一下我错过了什么吗?
如果要允许视图模型执行视图命令,则必须使用
HomeToolbar
控制 ICommand
属性,您可以将其绑定到外部 ICommand
实现(例如在视图模型类上定义)。 ICommand
。
HomeToolbar.xaml.cs
partial class HomeToolbar : UserControl
{
public ICommand SaveCommand
{
get => (ICommand)GetValue(SaveCommandProperty);
set => SetValue(SaveCommandProperty, value);
}
public static readonly DependencyProperty SaveCommandProperty = DependencyProperty.Register(
"SaveCommand",
typeof(ICommand),
typeof(HomeToolbar),
new FrameworkPropertyMetadata(default));
}
HomeToolbar.xaml
<UserControl>
<Button Content="Save data"
Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=SaveCommand}" />
</UserControl>
应用程序.xaml
<Application ...>
<Application.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type viewModel:HomeToolbarViewModel}">
<view:HomeToolbar SaveCommand="{Binding SaveDataCommand}"/>
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
HomeToolbarViewModel.cs
class HomeToolbarViewModel : INotifyPropertyChanged
{
public ICommand SaveDataCommand { get; }
}