Should MouseRightButtonDown work with EventToCommand? - wpf

Is the RightMouseDownEvent expected to work with EventToCommand?
I can bind a Command with PreviewMouseRightUp and PreviewMouseRightDown, but MouseRightButtonDown does nothing. Am I using the wrong event name -- is it that simple?
In the xaml -- i have both events bound to the same handler -- only one works (Preview...Up). I comment out each in turn, but only the Preview works.
Thoughts? Thanks!
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SetActivePaneCommand}" CommandParameter="{Binding PaneOne}" PassEventArgsToCommand="False" />
<cmd:EventToCommand Command="{Binding ListSelectionChangedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseRightButtonDown">
<cmd:EventToCommand Command="{Binding PreviewMouseRightButtonUpCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseRightButtonUp">
<cmd:EventToCommand Command="{Binding PreviewMouseRightButtonUpCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>

Some controls handle the MouseRightButtonDown event and doesn't let it propagate (e.g. MenuItem). You can test this easily if you're calling a code behind method instead of using a trigger and see if you'll reach a breackpoint in that method.
In your xaml:
MouseRightButtonDown="UIElement_OnMouseRightButtonDown"
In your code behind:
private void UIElement_OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{ }

Related

EventTrigger keydown give pressed key as command parameter

How to pass pressed key as command parameter in interraction?
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<i:InvokeCommandAction Command="{Binding SomeCommand}" CommandParameter="???PressedKey???"/>
</i:EventTrigger>
</i:Interaction.Triggers>
EventTrigger doesnt expose details about the event, it just registers to it.
https://msdn.microsoft.com/en-us/library/system.windows.eventtrigger(v=vs.100).aspx
You could instead write a Behavior, there you will control over which key etc:
https://wpftutorial.net/Behaviors.html
this code may solve your issue (It is for search with keypress by Binding) :
<TextBox Height="20" Margin="-30,2,0,0" Name="searchText" Text="{Binding SearchText}" Width="254" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="EditValueChanged">
<i:InvokeCommandAction Command="{Binding SearchFieldCommand}" CommandParameter="{Binding ElementName=searchText, Path=Text,UpdateSourceTrigger=PropertyChanged }" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
To better understand this code should be familiar with PropertyChanged

How to change data context of Interaction Trigger

I have a text box A with an interaction trigger. The Data Context of the text box is a property in the view model. However, the ClearCommand in defined in the view Model. How can I change the Data Context of the Interaction Triggers or its Command to the view model it self.
Thank you
<TextBox Name="TextBoxA"Text="{Binding myObject.TextPrp,UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding ClearCommand}"
CommandParameter="{Binding ElementName=TextBoxB,Path=Text}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
You have to bind to relative source like this
<TextBox Name="TextBoxA"Text="{Binding myObject.TextPrp,UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type YourUserControl}, Path=DataContext. ClearCommand}"
CommandParameter="{Binding ElementName=TextBoxB,Path=Text}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

wpf xaml page navigation without code behind

I am designing a prototype and want to navigate between pages in a wpf application.
Currently I am using code behind by handling events f.e.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Page2 page = new Page2();
this.NavigationService.Navigate(page);
}
This works, but it is unpleasant if you think of using MVVM later.
Is there a way to do this directly in xaml considering using a buttons click event?
Below code will show Page1 and Page2 in the Frame upon clicking the buttons.
It also shows Page2 on startup in the Frame.
Change namespace name in the Source of Frame below.
<Frame x:Name="frame" Content="Frame" Margin="80,80,144,122" Source="/WpfNavigation;component/Page2.xaml"/>
<Button x:Name="button" Content="Page1" HorizontalAlignment="Left" Margin="80,40,0,0" VerticalAlignment="Top" Width="75" Background="#FFF9F9F9">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction PropertyName="Source" TargetObject="{Binding ElementName=frame}">
<ei:ChangePropertyAction.Value>
<System:Uri>Page1.xaml</System:Uri>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button x:Name="button1" Content="Page2" HorizontalAlignment="Left" Margin="192,40,0,0" VerticalAlignment="Top" Width="75">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=frame}" PropertyName="Source">
<ei:ChangePropertyAction.Value>
<System:Uri>Page2.xaml</System:Uri>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
To use Blend assemblies :
Add reference to System.Windows.Interactivity and Microsoft.Expression.Interactions and following namespaces :
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
If we want to navigate using Button present in the Page itself, then we can do that using Source property of NavigationService object of Page class.
Page1.xaml :
<Button Content="Go to page2">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction PropertyName="Source" TargetObject="{Binding NavigationService, RelativeSource={RelativeSource AncestorType={x:Type Page}, Mode=FindAncestor}}">
<ei:ChangePropertyAction.Value>
<System:Uri>Page2.xaml</System:Uri>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
If you are using a button you can use a command binding. Your view model will have a property ICommand that does your navigate for you
<Button Command="{Binding Navigate}"/>

How to use an EventToCommand with an editable Combobox to bind TextBoxBase.TextChanged with a command?

I have an editable ComboBox.
<ComboBox IsEditable="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}"/>
</i:EventTrigger>
<i:EventTrigger EventName="TextBoxBase.TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
I use GalaSoft.MvvmLight.Command.EventToCommand to bind the SelectionChanged event.
I also would like to bind the TextChanged event, but it is a little bit tricky:
This event is only accessible by the ComboBox TextBoxBase property, and I can't find the proper way to bind this event.
You can see one of my unsuccessful attempt: SelectionChanged binding works fine, but TextChanged binding does not.
I also tried this syntax:
<ComboBox IsEditable="True">
<TextBoxBase>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBoxBase>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
But this won't even compile. I get an error "Type that can be instantiated expected" on the TextBoxBase tag.
Any idea ?
I know, very late response... but I hope it will help someone.
The problem here is that the EventTrigger class in Microsoft.Expression.Interactivity.dll uses reflection to find the event by the value of the EventName property and this won't work for attached events like TextBoxBase.TextChanged.
One option, which I use, is to implement your own custom EventTrigger class as described here and use this one instead of EventTrigger (the link there to CommandAction implementation is broken, but I managed to get it using internet archive).
Another option, which I don't like because it's not classic MVVM Command use, is to bind the Text property of the ComboBox to a property in the ViewModel and invoke the command from the ViewModel code on the setter, like this:
<ComboBox IsEditable="True"
Text="{Binding Text, Mode=TwoWay}" />
And in the ViewModel:
private string text;
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
if(CritereChangedCommand.CanExecute())
CritereChangedCommand.Execute();//call your command here
}
}
I have found a way to work around the problem:
I create an invisible TextBox, bound to the ComboBox, and I bind the command on the TextChanged event of the TextBox.
It's not pretty, but it works...
<ComboBox Name="CbRubrique" IsEditable="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<TextBox Text="{Binding ElementName=CbRubrique, Path=Text, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

(Caliburn Micro) Mapping a ActionMessage Methodname to a Child Object of the ViewModel

I would like to bind the methodname propererty of the caliburn.micro actionmessage to a method on a child object of the ViewModel.
How I would imagine it should work:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="MenuItemX.Clicked" />
</i:EventTrigger>
</i:Interaction.Triggers>
The problem here is that the methodname does not live directly on the viewmodel, but on a childobject of the viewmodel.
So in this case I would like to bind to:
ViewModel.MenuItemX.Clicked()
Current workaround is having a pass-through method on my viewmodel which smells.
You can set the actual target of the action (MenuItemX) using cal:Action.TargetWithoutContext attached property:
<Button cal:Action.TargetWithoutContext="{Binding MenuItemX}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="Clicked" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
or the shorter syntax:
<Button cal:Action.TargetWithoutContext="{Binding MenuItemX}"
cal:Message.Attach="Clicked" />

Resources