MvvmLight EventToCommand not working anymore - c#

I have encountered a rather strange problem using the GalaSoft - MVVM Light Toolkit in a Windows Phone 8 project.
Suddenly (after merging some stuff) all my EventToCommand calls are not working anymore. They worked before. I already tried to remove the MvvmLight toolkit and reference it again with Nuget, but the result stays the same.
One example:
MainMenuPage.xaml
<phone:PhoneApplicationPage
...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:commands="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
....>
<phone:PhoneApplicationPage.DataContext >
<Binding Source="{StaticResource MainMenuViewModel}"/>
</phone:PhoneApplicationPage.DataContext>
<!-- catch back key press -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="BackKeyPress">
<commands:EventToCommand
Command="{Binding BackKeyPressCommand}"
PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
MainMenuViewModel.cs
// back key press command
public RelayCommand<object> BackKeyPressCommand { get; set; }
public MainMenuViewModel()
{
BackKeyPressCommand = new RelayCommand<object>(
BackKeyPress,
(o) => true
);
...
}
private void BackKeyPress(Object o)
{
// handle back key press
}
This worked perfectly before, but now the BackKeyPress(Object o) Method never gets called anymore.
This happens for all EventToComamnd calls.
If I remove the xmlns tags, Resharper suggests to add this:
xmlns:command="http://www.galasoft.ch/mvvmlight"
Result of that:
The name "EventToCommand" does not exist in the namespace "http://www.galasoft.ch/mvvmlight"
Anyone encountered a similar problem or has an idea what could have caused this?

These namespaces are correct.
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:commands="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
But your PhoneApplicationPage has wrong DataContext.
DataContext="{Binding Path=MainMenuViewModel, Source={StaticResource Locator}}"
MainMenuViewModel is property in the ViewModelLocator:
public MainMenuViewModel MainMenuViewModel
{
get
{
return ServiceLocator.Current.GetInstance<MainMenuViewModel>();
}
}
Btw the argument of BackKeyPress is CancelEventArgs. You should use:
public RelayCommand<CancelEventArgs> BackKeyPressCommand { get; private set; }
this.BackKeyPressCommand = new RelayCommand<CancelEventArgs>(this.BackKeyPress)
private void BackKeyPress(CancelEventArgs e)
{
}

Windows Phone 8.1
Windows 8.1 Behavior SDK: How to use InvokeAction with InputConverter to pass arguments to a Command
Microsoft has developed it's own EventToCommand functionality. It's located in Behaviors SDK. Someone on stackoverflow told to get this SDK via Nuget. If you can't find the package in NuGet - get it in Add reference dialog.
(My add reference dialog may differs from original because of Productivity Power Tools extension)
Here is example of simple usage:
<ListBox ItemsSource="{Binding Persons, Mode=OneWay}"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{Binding DisplayPersonCommand}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</ListBox>

Related

WPF plugin architecture itemscontrol binding not working

We encountered an interesting behavior on .Net 4.5 (4.6.2 also tested).
The project has multiple plugin dlls.
main exe will load DataTemplates (view) and ViewModels from DLLs using MEF.
if StepView and StepVm and main frame code are in one project (not using MEF), The 2 buttons I show below are working.
if move StepView and StepVm to plugin dll, only second button will work. First one shows binding error in output console. need to talk to manager if I can post error msg here, just wpf standard binding error.
Can anyone share some insights here?
Thanks.
StepView
<UserControl
x:Class="StepView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ScriptHighlighter"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance local:StepVm}"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<ItemsControl x:Name="XItemsControl" ItemsSource="{Binding Names}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button
Content="Not Wokring in plugin mode"
Command="{Binding ElementName=XItemsControl, Path=DataContext.DeleteCommand}"
CommandParameter="{Binding}" />
<Button
Content="Wokrs in plugin mode"
Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
StepVm
public class StepVm:ViewModelBase
{
public StepVm()
{
this.Names = new List<string>(){"1", "2", "3"};
}
public List<string> Names { get; set; }
public ICommand DeleteCommand => new RelayCommand<string>(n =>
{
Debug.WriteLine($"logic to delete {n}");
});
}
Because MEF loads your UserControl dynamically into the Visual Tree, you are likely to have issues with NameScope, which I think is whats happening here.
WPF XAML Namescopes
To be honest, your use of ElementName binding is problematic, because your are in a DateTemplate which is an encapsulation boundary, so although it works outside MEF its not a typically supported scenario.

WPF&MVVM: Library System.Windows.Interactivity in not available anymore?

I need to add System.Windows.Interactivity.dll library via Reference Manager. In Visual Studio 2017, I did not find it. All search results that begins from System.Windows showed on the screenshot below:
I thought that this library becomes build-in in WPF project of current Visual Studio version, so when I added the bellow C# code, no warnings from IDE has been displayed:
private RelayCommand doubleCommand;
public RelayCommand DoubleCommand {
get {
return doubleCommand ??
(doubleCommand = new RelayCommand(obj => {
Phone phone = obj as Phone;
if (phone != null) {
Phone phoneCopy = new Phone {
Company = phone.Company,
Price = phone.Price,
Title = phone.Title
};
Phones.Insert(0, phoneCopy);
}
}));
}
}
However, when I added the following XAML markup, it says that Interaction, EventTrigger and InvokeCommandAction has not been found in clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity namespace:
<Window x:Class="MVVM_Tutorial.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MVVM_Tutorial"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<!-- ... -->
<Button Content="2x">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{Binding DoubleCommand}"
CommandParameter="{Binding SelectedPhone}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<!-- ... -->
</Window>
Has it relationship with System.Windows.Interactivity library or no, what have I do to solve this problem?
Currently, it's required to add System.Windows.Interactivity.WPF via NuGet package manager instead.
System.Windows.Interactivity.dll is not included in the .NET Framework but it is a part of the Expression Blend SDK which can be downloaded from here: https://www.microsoft.com/en-us/download/details.aspx?id=10801
Or you could download and reference the assembly using NuGet: https://www.nuget.org/packages/System.Windows.Interactivity.WPF/
I discovered that this is now a NuGet package called Microsoft.XAML.Behaviors, after landing on this question based on errors while trying to reference WPF Interactivity incorrectly in Visual Studo 2022. Hope it helps someone else who lands here.
Microsoft open sourced WPF Interactivity, after having available as part of WPF in various ways in the past. See blog article: link
Nuget Package:
Microsoft.XAML.Behaviors
XAML Reference:
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
Sample XAML code for binding a Command on TextBox losing focus:
<TextBox Name="txtFilterText" Text="{Binding SmartFilterText}" KeyUp="txtFilterText_KeyUp">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TextBox}, Path=DataContext.FilterSongsCommand}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

Best practice to handle ListView ItemClick in UWP using MVVM

I need to open a new view (item details) on mouse double click in ListView in UWP using MVVM. In WPF I used a command with a parameter and EventTrigger but Microsoft does not recommended to use it in UWP:
Triggers, EventTrigger, Actions and BeginStoryboard are not commonly used. These API mainly exist for compatibility in XAML originally used for Microsoft Silverlight...For events in control templates, use visual states and VisualStateManager.
As I understood it is used when you need to change visual state of the control but I need to open a new view.
How can I use VisualStateManager for my purpose?
There is how my XAML looked in WPF:
<ListBox x:Name="PersonsListControl" Grid.RowSpan="3" Grid.Row="0" Grid.Column="2"
ItemsSource="{Binding Path=PersonsProvider}"
ItemsPanel="{StaticResource PersonsListPanelTemplate}"
ItemTemplate="{StaticResource PersonsListItemTemplate}"
SelectedItem="{Binding SelectedPerson}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{Binding GetPersonDetailsCommand}"
CommandParameter="{Binding SelectedPerson}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
In UWP you can use {x:Bind ...} :
<ListBox ...
DoubleTapped="{x:Bind HandleDoubleTapped}" />
And in your ViewModel just create a method :
public void HandleDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
// your logic
}
References :
DoubleTapped
ListBox
EDIT:
#JörgenSigvardsson pointed out that x:Bind do not bind directly to the DataContext and you should create a proxy property/properties to access particular data from your page.
More on that can be read here

Binding Ui-Events to Commands in UWP [duplicate]

This question already has an answer here:
Binding UWP Page Loading/ Loaded to command with MVVM
(1 answer)
Closed 5 years ago.
I would like to bind any UI-Event directly to a command in my ViewModel.
Is there a way to do that in UWP?
I'm using the UWP Community Toolkit and would like to bind the Hamburger-Menu-Item-Click to an command.
Thanks
Tobias
Ok I found the solution for that.
You can find it here: Behaviors in UWP (Event trigger command error
I will repeat my steps here:
1 - Install Package
Install-Package Microsoft.Xaml.Behaviors.Uwp.Managed
2 - Include references to you view
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
3- Add the command to your ViewModel
public DelegateCommand MenuItemCommand { get; set; }
public void InitCommands()
{
MenuItemCommand = new DelegateCommand(MenuItemClicked);
}
private void MenuItemClicked()
{
//do something when clicked
}
4 - Bind the Click-Event of the menuitem to the command in the view (see the i:...-tag)
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:HamburgerMenu x:Name="HamburgerMenuControl"
PaneBackground="Black"
Foreground="White"
ItemTemplate="{StaticResource DefaultTemplate}"
OptionsItemTemplate="{StaticResource DefaultTemplate}"
ItemsSource="{Binding MenuItems}"
OptionsItemsSource="{Binding MenuOptionItems}"
>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="ItemClick">
<core:InvokeCommandAction Command="{Binding MenuItemCommand}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Frame x:Name="ContentFrame"/>
</controls:HamburgerMenu>
</Grid>
when I know click the menu-item it

CommandParameter of MetroEventToCommand doesn't work with control(Windows universal 10)

i want to bind an event using MetroEventToCommand library.
http://metroeventtocommand.codeplex.com/
It calls the method however it doesn't give the control as parameter. It's says it's null.
this is what i have.
<ScrollViewer x:Name="test">
<ListView/>
<metroEventToCommand:EventToCommandManager.Collection>
<metroEventToCommand:EventToCommand Command="{Binding RefreshCommand}" Event="ViewChanging" CommandParameter="{Binding ElementName=test, Mode=TwoWay}"/>
</metroEventToCommand:EventToCommandManager.Collection>
</ScrollViewer>
public RelayCommand<ScrollViewer> RefreshCommand { get; set; }
private void init()
{
RefreshCommand = new RelayCommand<ScrollViewer>(Refresh);
}
private void Refresh(ScrollViewer o)
{
if (o != null)
{
}
}
thanks in advance.
OK... not quite an answer, but I can't put code in a comment. I put together a quick app using MVVM Light and using the Interactivity library instead of metroToEventCommand.
I can pass it from hooking up an event handler (of course)
private void onViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
{
vm.RefreshCommand.Execute(this.test);
}
I can also get it to fire the command WITH the parameter using the Loaded event or PointerEntered event
<ScrollViewer x:Name="test" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="PointerEntered">
<Core:InvokeCommandAction Command="{Binding RefreshCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=test}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<ListView x:Name="myList"/>
</ScrollViewer>
However, the Interactivity dll throws an exception (Cannot add instance of type 'Microsoft.Xaml.Interactions.Core.EventTriggerBehavior' to a collection of type 'Microsoft.Xaml.Interactivity.BehaviorCollection'.) when trying to use the ViewChanging, ViewChanged, DirectManipulationCompleted, etc. events - whether a parameter is used or not. ManipulationCompleted does not fire the command (I've seen hints that commands cannot be bound to routed events).
So, it would seem that the concept works - but only for certain event types. I'm sorry that isn't a solution to your challenge, but hopefully it is some additional information to help your attempts.

Categories