Execute function across user controls wpf c# - wpf

I have a MainWindow in my application.
Within the MainWindow I dynamically host a user control (ucA).
Within ucA i have another user control (ucB).
When I click the save button on ucB, i need to execute a routine on ucA.
How can I reference the routine on ucA?

Here are some ways I can think of :-
You can use CallMethodAction in your xaml to call a method of parent usercontrol. The code goes like this :-
<UserControl x:Class="WpfApplication.ucB"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Height="300" Width="300">
<StackPanel>
<Button Content="Save" x:Name="SaveButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=2, AncestorType=UserControl}}"
MethodName="MethodToCallOnucA" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</StackPanel>
This way you can call the method on ucA which is the parent of ucB. BUT there is a big limitation to this way of calling methods from xaml. The limitation is that in this case your `MethodToCallOnucA' must return void and must have no method parameters.
If you must send parameters to your method then you need to follow the SECOND approach over here. For this we need to use Commands to make a call to method of Usercontrol. You need to change the button's code in the xaml above like this :-
<Button Content="Save" x:Name="SaveButton" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource FindAncestor,AncestorLevel=2, AncestorType=UserControl}, Path=DoActionCommand}" CommandParameter="ValueToSendAsMethodParameter" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Here DoActionCommand is a ICommand property defined in your usercontrol ucA and this ICommand points to the method you need to call in ucA.

Related

WPF mvvm wizard

I am implementing WPF MVVM Wizard and I am wondering about the right approach of performing a DoOperation when a new Wizard’s Page (UserControl) is loaded.
The DoOperation is implemented on the MyWizard.ViewModal class while the UserControl Load is happening at the MyWizard.View namespaces.
How can I connect between the UserControl loaded event to the DoOperation api?
I tried the following:
<xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Path=RunOperation}"/
</i:EventTrigger>
</i:Interaction.Triggers>
RunOperation calls DoOperation.
it doesn’t work, RunOperation is not being called.
This is the right approach or there is a better way to perform an operation at the MyWizard.ViewModal class?
Your approach should work. Have you checked your output console for binding errors? Is RunOperation a command? Is the DataContext of the UserControl already set, when the Loaded event is raised? Have you implemented the triggers like this in your UC?
<UserControl x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Path=RunOperation}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
...
</Grid>
</UserControl>

Using an EventTriggers in a DataGridTemplateColumn

I am using Silverlight 5 and in a view I have a Button that, when clicked, loads a particular state. This is done using an EventTrigger and the GoToStateAction markup like so:
<Button x:Name="..." Content="...">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="MyState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The above works swimmingly, but if I move the Button into a DataGridTemplateColumn it no longer works. Specifically, the app compiles without error and the DataGrid shows the button in a column, but when I click the button the state is not transitioned to.
<data:DataGrid ...>
<data:DataGrid.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="..." Content="...">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="MyState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
Is it not possible to have EventTriggers in a DataGridTemplateColumn? Or do I need to declare them using alternate syntax?
Thanks
The GoToStateAction reference states that, if no target is specified, it will walk up the visual tree and apply the state change on the first element it finds that defines states. In your second case, I believe that some elements of the DataGrid visual tree (cells, rows, etc) may be taken in account before your usercontrol, thus the behavior you've seen.
Since you are using Silverlight 5, you can try to set the TargetObject property of the action to your desired control, using a binding with a relative source looking of a ancestor of the type of UserControl.
<ei:GoToStateAction StateName="MyState" TargetObject="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"/>

Wpf checkbox trigger

Trying to bind the click or checked event on a WPF chekbox to a command in my viewmodel, but im unsure on the technique and the event names, can anyone point me in the right direction?
For now the code compiles but the the trigger does not call the FooCommand
<CheckBox IsChecked="{Binding PartData.ReportIncluded, Mode=TwoWay}"
VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<i:InvokeCommandAction Command="{Binding FooCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Looks like you're missing the "On" prefix of your event, i.e. OnMouseLeftButtonDown or OnPreviewMouseLeftButtonDown

Routed Events of TextBlock

How to fire RoutedEvents of TextBlock in ViewModel from code behind in wpf.
Kindly let me know, how I can bind routed events in wpf code behind. Thanks
Well I use this (you will need System.Windows.Interactivity in Silverlight, but I suspect it's similar in WPF):
xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL4"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<TextBlock Text="{Binding InputValue, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding InputValueGotFocusCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
You can do this easy in Blend

CallMethodAction: How do I refer to instance of a view as being TargetObject

I know you'll use this to invoke method on the ViewModel, but just out of curiosity, how would you use to wire an event handler on the instance of the view, equivalent to wiring it in code behind.
The TargetObject is the object which has the method to be invoked, if you have the method in your window code-behind then the object is the window itself. You can bind to it by its name:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
...etcetera...
x:Name="UserControl">
So your CallMethodAction would be:
<ei:CallMethodAction MethodName="MyMethod"
TargetObject="{Binding ElementName=UserControl, Mode=OneWay}"/>
I think you are probably after something like this (ignore that this specific example is best done with a command).
<Button Content="Click this">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="SomeMethod" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

Resources