I've got this WPF
MVVM
window app, that I'm a bit stuck on KeyBinding on buttons.
What I've done so far is create an ObservableCollection
of CommandVM's. Which hold a bunch of properties to set up button properties in the XAML.
In my MainWindow VM I initialize an OC of CommandVMs like so:
public ObservableCollection<CommandVM> Commands { get; set; }
CommandVM cmdVMInsert;
CommandVM cmdVMEdit;
CommandVM cmdVMDelete;
CommandVM cmdVMCommit;
CommandVM cmdVMRollback;
CommandVM cmdVMMerge;
public MainWindowViewModel()
{
cmdVMInsert = new CommandVM { LeftMargin = 0, CommandDisplay = "Authorize", IconGeometry = Application.Current.Resources["InsertIcon"] as Geometry, BoundKey = Key.OemPlus, Message = new CommandMessage { Command = CommandType.Insert }, IsEnabled = false };
cmdVMEdit = new CommandVM { LeftMargin = 0, CommandDisplay = "Edit", IconGeometry = Application.Current.Resources["EditIcon"] as Geometry, BoundKey = Key.Space, Message = new CommandMessage { Command = CommandType.Edit }, IsEnabled = false };
cmdVMDelete = new CommandVM { LeftMargin = 0, CommandDisplay = "Delete", IconGeometry = Application.Current.Resources["DeleteIcon"] as Geometry, BoundKey = Key.Delete, Message = new CommandMessage { Command = CommandType.Delete }, IsEnabled = false };
cmdVMCommit = new CommandVM { LeftMargin = 25, CommandDisplay = "Commit", IconGeometry = Application.Current.Resources["SaveIcon"] as Geometry, BoundModifierKeys = new ModifierKeys[] { ModifierKeys.Control }, BoundKey = Key.S, Message = new CommandMessage { Command = CommandType.Commit }, IsEnabled = false };
cmdVMRollback = new CommandVM { LeftMargin = 0, CommandDisplay = "Rollback and refresh", IconGeometry = Application.Current.Resources["RefreshIcon"] as Geometry, Message = new CommandMessage { Command = CommandType.Rollback }, IsEnabled = false };
cmdVMMerge = new CommandVM { LeftMargin = 0, CommandDisplay = "Merge", IconGeometry = Application.Current.Resources["RefreshIcon"] as Geometry, Message = new CommandMessage { Command = CommandType.Merge }, IsEnabled = true };
ObservableCollection<CommandVM> commands = new ObservableCollection<CommandVM>
{
cmdVMInsert,
cmdVMEdit,
cmdVMDelete,
cmdVMCommit,
cmdVMRollback,
cmdVMMerge
};
Commands = commands;
RaisePropertyChanged("Commands");
}
The CommandVM class
public class CommandVM : ViewModelBase
{
public bool VM_StyleCommand = false;
private int f_LeftMargin = 0;
public int LeftMargin
{
get
{
return f_LeftMargin;
}
set
{
f_LeftMargin = value;
}
}
private string f_VM_DisplayName = "";
public string VM_DisplayName
{
get
{
return f_VM_DisplayName;
}
set
{
f_VM_DisplayName = value;
RaisePropertyChanged("CommandDisplay");
}
}
private string f_CommandDisplay = "";
public string CommandDisplay
{
get
{
string result = f_CommandDisplay;
if (VM_StyleCommand && !VM_DisplayName.Equals(""))
{
result = result + " " + VM_DisplayName;
}
return result;
}
set
{
f_CommandDisplay = value;
RaisePropertyChanged();
}
}
public CommandMessage Message { get; set; }
public RelayCommand Send { get; private set; }
public Geometry IconGeometry { get; set; }
public ModifierKeys[] BoundModifierKeys;// { get; set; }
public Key BoundKey { get; set; }
public string GetBoundKey
{
get
{
return BoundKey.ToString();
}
}
public string GetBoundModifierKeys
{
get
{
string builder = "";
if (BoundModifierKeys != null)
{
foreach (var ModifierKey in BoundModifierKeys)
{
if (!builder.Equals(""))
builder += "+";
builder += ModifierKey.ToString();
}
}
return builder;
}
}
private bool f_IsEnabled = false;
public bool IsEnabled
{
get
{
return f_IsEnabled;
}
set
{
f_IsEnabled = value;
RaisePropertyChanged("IsEnabled");
}
}
private bool canExecute = true;
public bool CanExecute
{
get
{
return canExecute = IsEnabled;
}
set
{
canExecute = value;
RaiseCanExecuteChanged();
}
}
public CommandVM()
{
Send = new RelayCommand(() => SendExecute());
}
private void SendExecute()
{
Messenger.Default.Send<CommandMessage>(Message);
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
In the XAML:
<Window x:Class="MobileDeviceAuthenticator.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:MobileDeviceAuthenticator"
xmlns:conv="clr-namespace:WPF_Converters;assembly=WPF_Converters"
mc:Ignorable="d"
Title="Device Authorization"
Height="381"
Width="879" >
<Window.Resources>
<DataTemplate DataType="{x:Type local:MobileDeviceRequestsViewModel}">
<local:MobileDeviceRequestsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:UserMobileDevicesViewModel}">
<local:UserMobileDevicesView/>
</DataTemplate>
<conv:MarginConverter x:Key="marginConverter"/>
</Window.Resources>
<Grid x:Name="GridContainer" Margin="5" >
<Grid Margin="0,25,0,0" AllowDrop="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
ItemsSource="{Binding Commands}"
BorderBrush="Transparent"
FontSize="12" FontWeight="Bold"
ScrollViewer.CanContentScroll="False" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Send}"
BorderThickness="0"
Margin="{Binding LeftMargin, Converter={StaticResource marginConverter}}"
Padding="0"
IsEnabled="{Binding IsEnabled, Mode=TwoWay}"
>
<Path Data="{Binding IconGeometry}" Stretch="Uniform"
Style="{StaticResource PathOpacityStyle}"
Fill="{StaticResource MidDullBrush}" Width="25" Height="25"/>
<Button.ToolTip>
<TextBlock Text="{Binding CommandDisplay, Mode=TwoWay}"/>
</Button.ToolTip>
<Button.InputBindings>
<KeyBinding Key="{Binding GetBoundKey}"
Modifiers="{Binding GetBoundModifierKeys}"
Command="{Binding Send}"/>
</Button.InputBindings>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</Window>
The buttons themselves work nicely, however, the Button.KeyBinding
does not, I've seen other KeyBindings on other solutions that get attached at Window
level.
My question is: Is there a way with my current CommandVM
with the Key
properties to somehow hookup the KeyBindings
to the Window
[Edit] Changing the question a little to achieve the same result.
Can I achieve the same sort of thing, but as below, still using the ObservableCollection of commands and some sort of ItemsControl iteration
<Window.InputBindings>
<!-- Start items iteration with ItemsSource set to 'Commands'-->
<KeyBinding Key="{Binding GetBoundKey}" Modifiers="{Binding GetBoundModifierKeys}" Command="{Binding Send}"/>
<!-- end iteration -->
</Window.InputBindings>