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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
OnTheFly
  • 2,059
  • 5
  • 26
  • 61

3 Answers3

14

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)

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 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" – OnTheFly Nov 21 '11 at 14:26
  • @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... – H.B. Nov 21 '11 at 16:16
  • I had a mistake in my project configuration. Now I use .NET 4.0. I get an exception that my CommandParameter is null... – OnTheFly Nov 21 '11 at 17:32
  • @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](http://blogs.msdn.com/b/wpfsldesigner/archive/2010/06/30/debugging-data-bindings-in-a-wpf-or-silverlight-application.aspx), unless of course you checked for binding errors already. – H.B. Nov 21 '11 at 21:17
  • CommandParameter is not a DependencyProperty and can not be bound. – Adam Mills Nov 22 '11 at 16:25
  • @AdamMills: No, it **is** a DP in **.NET 4**. Don't assume that everyone is using outdated frameworks. – H.B. Nov 22 '11 at 16:29
  • Thank you! I couldn't find this answer any any blogs or even after an hour of google searches! Worked like a charm. – Paurian Mar 05 '18 at 13:25
  • @Paurian: Glad it helped :) – H.B. Mar 05 '18 at 14:17
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!

Emy
  • 91
  • 2
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>
Adam Mills
  • 7,719
  • 3
  • 31
  • 47
  • 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... – OnTheFly Nov 21 '11 at 15:47
  • The xaml i have posted works for me, Dataresource classes come from the posted URL. – Adam Mills Nov 22 '11 at 16:49