Passing a Command Parameter from a Datagrid through a Keybinding
Asked Answered
V

3

5

I've a wpf specific problem. I'm trying to delete a Row from a Datagrid, by defining a Keybinding that passes the selected Row of the Datagrid as a Commandparameter to a Command.

This is my Keybinding:

<UserControl.Resources >
    <Commands:CommandReference x:Key="deleteKey" Command="{Binding DeleteSelectedCommand}"/>
</UserControl.Resources>

<UserControl.InputBindings>
    <KeyBinding Key="D" Modifiers="Control" Command="{StaticResource deleteKey}"/>
</UserControl.InputBindings>

I know this basically works, because I can debug up to the DeleteSelectedCommand. However there flies an Exception because the DeleteSelectedCommand expectes a Row of the Datagrid to delete as Call Parameter.

How can I pass the SelectedRow through the Keybinding?

I want to do this only in the XAML, if possible, without changing the Code Behind.

Veliz answered 21/11, 2011 at 14:10 Comment(0)
R
2

Rather than trying to use a command parameter, create a property to store the selected row in:

private Model row;

 public Model Row
     {
         get { return row; }
         set
         {
             if (row != value)
             {
                 row = value;
                 base.RaisePropertyChanged("Row");
             }
         }
     }

where Model is the class of the objects your grid is displaying. Add the selectedItem property on the datagrid to use the property:

<DataGrid SelectedItem="{Binding Row, UpdateSourceTrigger=PropertyChanged}"/> 

then have your command pass through the row to the method:

    public ICommand DeleteSelectedCommand
     {
         get
         {
             return new RelayCommand<string>((s) => DeleteRow(Row));
         }
     }

and for your keybindings:

 <DataGrid.InputBindings>
            <KeyBinding Key="Delete" Command="{Binding DeleteSelectedCommand}" />
        </DataGrid.InputBindings>

Hope that helps!

Rosarosabel answered 22/11, 2011 at 9:40 Comment(0)
L
15

If your DataGrid has a name you can try to target it that way:

<KeyBinding Key="D" Modifiers="Control" Command="{StaticResource deleteKey}"
            CommandParameter="{Binding SelectedItem, ElementName=myDataGrid}"/>

(Note: CommandParameter is only bindable in .NET 4 (and presumably the following versions) as it was changed into a dependency property)

Lilywhite answered 21/11, 2011 at 14:17 Comment(8)
If I try this there was a XamlParseException that says, that I can't bind a CommandParameter in a KeyBinding, bindings can only be selected for "DependencyProperty"Veliz
@user539484: What version of .NET are you using? If you are on an older version you should make that clear via the question tags, in v4.0 that property is a dependency property...Lilywhite
I had a mistake in my project configuration. Now I use .NET 4.0. I get an exception that my CommandParameter is null...Veliz
@user539484: Then you might have misspelled the name or it's not in the scope of the keybinding (e.g. it's in some Template/DataTemplate). Or of course the SelectedItem is actually null. There might be some other possibilities of course. You better debug the binding, unless of course you checked for binding errors already.Lilywhite
CommandParameter is not a DependencyProperty and can not be bound.Xerophyte
@AdamMills: No, it is a DP in .NET 4. Don't assume that everyone is using outdated frameworks.Lilywhite
Thank you! I couldn't find this answer any any blogs or even after an hour of google searches! Worked like a charm.Swick
@Paurian: Glad it helped :)Lilywhite
R
2

Rather than trying to use a command parameter, create a property to store the selected row in:

private Model row;

 public Model Row
     {
         get { return row; }
         set
         {
             if (row != value)
             {
                 row = value;
                 base.RaisePropertyChanged("Row");
             }
         }
     }

where Model is the class of the objects your grid is displaying. Add the selectedItem property on the datagrid to use the property:

<DataGrid SelectedItem="{Binding Row, UpdateSourceTrigger=PropertyChanged}"/> 

then have your command pass through the row to the method:

    public ICommand DeleteSelectedCommand
     {
         get
         {
             return new RelayCommand<string>((s) => DeleteRow(Row));
         }
     }

and for your keybindings:

 <DataGrid.InputBindings>
            <KeyBinding Key="Delete" Command="{Binding DeleteSelectedCommand}" />
        </DataGrid.InputBindings>

Hope that helps!

Rosarosabel answered 22/11, 2011 at 9:40 Comment(0)
X
0

There is a property called CommandParameter on KeyBinding, anything set here will be passed through. It however is not a dependency property (in 3.5, for 4.0 see H.B.'s answer) as you have found with the Command, inputbindings are out of the inheritance tree and so they didn't bother making them DP's.

You will need to use the same solution you used for binding the command. There's an example here, http://www.wpfmentor.com/2009/01/how-to-add-binding-to-commandparameter.html

 <DataGrid x:Name="grid">
  <DataGrid.Resources>
    <WpfSandBox:DataResource x:Key="cp" BindingTarget="{Binding SelectedItem, ElementName=grid}" />
  </DataGrid.Resources>
  <DataGrid.InputBindings>
    <KeyBinding Key="q" Modifiers="Control" Command="{x:Static WpfSandBox:Commands.Delete}">
      <KeyBinding.CommandParameter>
        <WpfSandBox:DataResourceBinding DataResource="{StaticResource cp}"/>
      </KeyBinding.CommandParameter>
    </KeyBinding>
  </DataGrid.InputBindings>
  <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding Value}"  />
    <DataGridTextColumn Binding="{Binding Value}"  />
  </DataGrid.Columns>
</DataGrid>
Xerophyte answered 21/11, 2011 at 14:30 Comment(2)
We tried that and it almost works. The only Problem is, that we got an InvalidCastException when the CommandParameter is being cast to Datagrid. The Errormessage says that an Object of the Type System.Object can't be cast to a Datagrid...Veliz
The xaml i have posted works for me, Dataresource classes come from the posted URL.Xerophyte

© 2022 - 2024 — McMap. All rights reserved.