I have the following structure in my UI. I am trying to have a checkbox, which will fire a command and I want to get the row as command parameter.
<telerik:GridViewColumn Header="Rbl">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}, Path=DataContext.IsRblMappedChangedCommand}"
CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=telerik:GridViewRow}}"/>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
This triggers my command in the view model, and I get the data context as command parameter. The issue comes when I set the IsChecked property of the checkbox.
<DataTemplate>
<CheckBox IsChecked="{Binding IsRblMapped}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}, Path=DataContext.IsRblMappedChangedCommand}"
CommandParameter="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=telerik:GridViewRow}}"/>
</DataTemplate>
After this I start getting the data context as null. Any idea why this happens and how to fix it?
The title pretty much explains the question.
I have the following in the view in a Template:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SizeChanged">
<i:InvokeCommandAction>
<i:InvokeCommandAction.Command>
<Binding Source="{StaticResource eventBindingHelper}" Path="DataC.SizeChangedCommand"></Binding>
</i:InvokeCommandAction.Command>
<i:InvokeCommandAction.CommandParameter>
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type igDP:LabelPresenter}}"/>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
The command binding works if it's bound to the viewmodel. But i would like to bind it to a behavior and i can't seem to find a way.
Make sure to add the reference to Behaviours SDK, and then you can do the following:
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped" SourceObject="{Binding ElementName="Control to trigger"}"> //Bind behaviour the the element you want to trigger
<Core:InvokeCommandAction Command="{Binding Command}" CommandParameter="{Binding parameter}"/> // Bind command and parameter to behaviour
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
Then you can switch between the EventNames in EventTriggerBehaviour to trigger the controls as you want.
I used
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tapped"
SourceName="myControlName">
<i:InvokeCommandAction Command="{Binding Command}"
CommandParameter="{Binding parameter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Similar to the accepted answer but with different namespaces/class names.
I want to execute a command when the user selects a row in a DataGrid.
I see it is possible to wrap cell contents in buttons (although I don't want the button style) - but I don't want to do it at the cell-level.
I also see it's possible to use behaviours to link a command to an event. But preferably I should not have to resort to behaviors for such a common task.
Is it possible to do this via plain old command databinding?
So: 1) user clicks DataGrid row 2) command on view model is fired.
You should use "Interactivity" assembly and SelectionChanged event.
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding People}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" />
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
Where "i" is namespace:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Also you can write binding to SelectedItem property of the DataGrid and in the set accessor you can invoke your command, but the first solution that i presented you above is better.
If you want to invoke command from main view model and pass SelectedItem from DataGrid you can use CommadParameter:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding MyCommand}"
CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
When items has own command you can use following code:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=SelectedItem.MyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Or if elements has own view model that is assigned to it's DataContext, you can use following code:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding Path=SelectedItem.DataContext.MyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
Be advised that #kmatyaszek's answer is outdated in .NET 5.0 and above, we should use Microsoft.Xaml.Behaviors instead of Microsoft.Expression.Interactions.
So the i in the namespace should be:
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
See here for details.
I am trying to bind the CommandParameter of a command on a TreeView to the TreeView itself's selected item without naming the TreeView.
Code:
<TreeView>
<ACB:CommandBehaviourCollection.Behaviours>
<ACB:BehaviourBinding Event="SelectedItemChanged" Command="{Binding CmdSelectedItemChanged}" CommandParameter="{Binding SelectedItem, Source={RelativeSource Mode=Self}}"></ACB:BehaviourBinding>
</ACB:CommandBehaviourCollection.Behaviours>
</TreeView>
I am using AttachedCommandBehaviour in the above example.
Can someone explain how I can achieve this?
Thanks,
Alex.
Try out following:
<ACB:BehaviourBinding
Event="SelectedItemChanged"
Command="{Binding CmdSelectedItemChanged}"
CommandParameter="{Binding
Path = PlacementTarget
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type TreeView}}}" />
I'm trying to bind a command to a menuitem in WPF. I'm using the same method that's been working for all my other command bindings, but I can't figure out why it doesn't work here.
I'm currently binding my commands like this:
Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MyCommand}"
This is where it goes wrong (this is inside a UserControl)
<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}"
Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" CommandParameter="{Binding Name}"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RemoveCommand}"/>
</ContextMenu>
</Button.ContextMenu>
...
The first command binding works like it should, but the second one refuses to do anything.
I've tried changing the ancestor level and naming my Control to access it through ElementName instead of RelativeSource, but still no change. It keeps saying "Cannot find source for binding with reference..."
What am I missing?
(Edit) Since you mentioned this is in an ItemsControl's template, things are different:
1) Get the BindingProxy class from this blog (and read the blog, as this is interesting information): How to bind to data when the DataContext is not inherited.
Basically the elements in the ItemsControl (or ContextMenu) are not part of the visual or logical tree, and therefore cannot find the DataContext of your UserControl. My apologies for not writing more on this here, but the author has done a good job explaining it step by step, so there's no way I could give a complete explanation in just a few lines.
2) Do something like this: (you may have to adapt it a bit to make it work in your control):
a. This will give you access to the UserControl DataContext using a StaticResource:
<UserControl.Resources>
<BindingProxy
x:Key="DataContextProxy"
Data="{Binding}" />
</UserControl.Resources>
b. This uses the DataContextProxy defined in (a):
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" CommandParameter="{Binding Name}"
Command="{Binding Path=Data.RemoveCommand, Source={StaticResource DataContextProxy}}"/>
</ContextMenu>
This has worked for us in things like trees and datagrids.
ContextMenu is in different logical tree, that's why RelativeSource doesnt work. But context menu inherit DataContext from its "container", in this case it is Button. It is enough in common case but in your case you need two "data contexts", of ItemsControl item and of ItemsControl itself.
I think you have no other choice but combine your view models into one, implement custom class to be used as ItemsControl item data context and contain both "Name" and "Remove command" or your item's view model can define RemoveCommand "proxy", that would call parent command internally
EDIT:
I slightly changed Baboon's code, it must work this way:
<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}"
Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
CommandParameter="{Binding Name}"
Command="{Binding Path=PlacementTarget.Tag.DataContext.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
koshdim is spot on, it works like a charm!! Thanks Koshdim
I modified his code to fit in my context menu
<DataGrid
AutoGenerateColumns="False"
HeadersVisibility="Column"
Name="dgLosses"
SelectedItem="{Binding SelectedItem, Mode= TwoWay}"
AllowDrop="True"
ItemsSource="{Binding Losses}"
Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">
<DataGrid.ContextMenu >
<ContextMenu >
<MenuItem Header="Move to Top " Command="{Binding PlacementTarget.Tag.MoveToTopCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
<MenuItem Header="Move to Period 1" Command="{Binding PlacementTarget.Tag.MoveToPeriod1Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
<MenuItem Header="Move to Period 2" Command="{Binding PlacementTarget.Tag.MoveToPeriod2Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
<MenuItem Header="Move to Period 3" Command="{Binding PlacementTarget.Tag.MoveToPeriod3Command,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" ></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
That's a tricky issue, sure marginally you will find a quick workaround, but here is a no-magic-solution:
<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}"
Tag={Binding}
Command = "{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ConnectCommand}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
CommandParameter="{Binding Path=PlacementTarget.Tag.Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
Command="{Binding Path=PlacementTarget.Tag.RemoveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
...
It boils down to using the Tag of the PlacementTarget (the Button here).