CommandParameter always passes EventArgs with ElementName binding, no actual binded value - c#

So, with the Behavior SDK I want to bind a Pivot event to my viewmodel. The binding looks like this:
<Pivot Grid.Row="1" x:Name="pvtMain"
ItemsSource="{Binding Items}"
HeaderTemplate="{StaticResource PivotHeaderTemplate}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="PivotItemLoading">
<Core:InvokeCommandAction Command="{Binding LoadAdditionalData}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Pivot>
The action that is performed in the Viewmodel looks like this:
private void _CommandLoadAdditionalData(object parameter) {
var test = (parameter as PivotItemEventArgs);
}
The problem is as follows: I'm getting the error: type or namespace name 'PivotItemEventArgs' could not be found (are you missing a using directive or an assembly reference?).
But when I run the project everything works just fine. When dig a little deeper, PivotItemEventArgs does reside in the Windows.UI.Xaml.Controls, but it won't be found in the Shared project.
I'm guessing this happens because a pivot item is no Windows 8 control.
Now I just want the SelectedItem to be passed, instead of EventArgs. I changed my CommandParameter to the following:
<Core:InvokeCommandAction Command="{Binding LoadAdditionalData}"
CommandParameter="{Binding ElementName=pvtMain, Path=SelectedItem}" />
Still, the value is still PivotItemEventArgs. Am I missing something?

So after some struggling, I've stumbled upon the 'solution'.
I bound the command on the PivotItemLoading event. Somehow, at the first load event trigger, the parameter is always of type PivotItemEventArgs.
However, after the second loading, the correct object (the SelectedItem) is being passed along!
I don't know the exact reason, but it's good to know this works.

Related

Context menu binding never gets executed

I have ListView control in my view with it's own viewmodel A. I have made a seperate UserControl to use as ListViewItem, because it's styling takes a lot of space. In this ListViewItem I have a button, which is binded to viewmodel A and it works fine.
As the context menu has it's own visual tree and cannot bind via ancestor, I have used binding proxy, to solve this issue. I have tweaked it a little so it worked for my particular case, because if it just used {Binding} it would bind to item's model, not listview's viewmodel.
<helpers:BindingProxy x:Key="proxy" Data="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}"/>
To check if the binding is correct I've used a converter as a way just to have a breakpoint to check source. Everything was good and I was getting my viewmodel right there.
Now, when I try to bind to this in my context menu
<UserControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Open"
Command="{Binding DataContext.OpenChatCommand, Source={StaticResource proxy}, Converter={StaticResource DataBindingDebugConverter}}"
CommandParameter="{Binding}"/>
</ContextMenu>
</UserControl.ContextMenu>
The command never gets called. I added converter to see if something is wrong, but it turns out, I never get to my converter, which in turn means this code never gets executed.
Anyone with any ideas why this is happening and how to solve this is welcome.
I think it's the compiler malfunctioning though
I just did a brief readup on that "binding proxy" you mentioned, but as far as I know, DataGridTextColumn is in the same Visual Tree as its DataGrid, just that its DataContext is bound to its data.
For ContextMenu, it's totally different. This one really has a separate tree from its parent. There is no point in using a proxy object in resources, because it is from a different visual tree. When you use StaticResource, WPF will search upwards through its visual tree, level by level, inside those elements' Resource property (which is a ResourceDictionary).
One way is to make that proxy into a singleton, and use Source={x:Static helpers:BindingProxy.Instance}. Of course using this means that your proxy can only be used by a single View, or else something unexpected would happen.
The other way is to make use of PlacementTarget property of the ContextMenu.
<ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}">
This is the preferred way, but you need to make sure the parent's DataContext is really the VM that you need.
Edit
There is no super elegant way to do it the MVVM way. The best way is probably through the use of Tag property.
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag,
RelativeSource={RelativeSource Self}}">
ListView Control:
<MyControl:MyListViewItem .... Tag="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type MyControl:MyListViewView}}}"}" ...>

Problems adding Blend behavior to DatePicker

I'm trying to add a Blend behavior to a DatePicker control to bind an MVVM-Light RelayCommand to the DateChanged event like so:
<DatePicker Date="{Binding SelectedDate, Mode=TwoWay}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="DateChanged">
<Core:InvokeCommandAction Command="{Binding DateChangedCommand, Mode=OneWay}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</DatePicker>
I'm using the following definitions:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
However, I keep getting the following error:
WinRT information: Cannot add instance of type
'Microsoft.Xaml.Interactions.Core.EventTriggerBehavior' to a collection of type
'Microsoft.Xaml.Interactivity.BehaviorCollection'.
I have successfully used Blend behaviors in this way many other times in my project (and with other controls in the same Xaml file) to bind an event to a command, and the DatePicker control is the only one that has thrown an error. Is there another way to accomplish this or are WinRT DatePickers limited in this way?

Binding a function to the MouseDown event in xaml?

im Working on learning WPF and C# programming at the moment but im struggling with understanding bindings etc.
I am stuck on "binding" functions or commands to my XAML object which is in a grid.
<Image x:Name="BlkRook1" Source="../Data/BlkRook.png" Grid.Row="{Binding Path=ChessPieces[0].Row}" Grid.Column="{Binding Path=ChessPieces[0].Column}" MouseDown="{Binding Path=ChessPieces[0].Move()}"/>
The code MouseDown="{Binding Path=ChessPieces[0].Move()}" Does not work but displays what im trying to achive
In my viewmodel i have defined a list which i have filled up with instances of my diffrent chesspieces, and then im planning on binding each image to a instance from that list.
im trying to do is bind the MouseDown function at the moment, it seems like if i place the function in the Mainwindow.xaml.cs file it can access it. But i want it to be able to access it from the model
Mainwindow.xaml.cs
namespace TheGame.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ChessBoardViewModel();
}
}
}
The BlkRook object has defined Row, column, name and a function move at the moment.
Error Message:
"'TheGame.Views.MainWindow' does not contain a definition for 'Move' and no extension method 'Move' accepting a first argument of type 'TheGame.Views.MainWindow' could be found (are you missing a using directive or an assembly reference?)"
So.. How do i bind a function that is defined in a Model-object to a XAML object?
Thanks
/Martin
You can't bind to methods. You are using MVVM so I would suggest you to use attached properties in combination with commands. You could also use the MouseBinding class: http://msdn.microsoft.com/en-us/library/system.windows.input.mousebinding(v=vs.110).aspx.
Commandbinding is explained quite well here: http://www.danharman.net/2011/08/05/binding-wpf-events-to-mvvm-viewmodel-commands/
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown" >
<i:InvokeCommandAction Command="{Binding MouseDownCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

Can't use long syntax for ActionMessage in Caliburn.Micro

I'm trying to create an action for an attached event which I don't think CM supports out of the box.
This question/answer shows how to do this
using attached events with caliburn micro Message.Attach
but it requires using the long CM ActionMessage syntax, however, when I try to do this I get an 'ActionMessage does not exist in the XML namespace ' where blah is the CM namespace.
All of the examples also show this syntax; at the moment I've just put the code into the view which casts the DataContext to the ViewModel type and calls the appropriate method (I don't like this approach though as it couples the view to the VM and it's inconsistent with the rest of the app)
Anyone have any ideas why I can't see the ActionMessage?
e.g.
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<!-- this line throws the error -->
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs" />
</cal:ActionMessage>
</Helpers:RoutedEventTrigger>
</i:Interaction.Triggers>
I'm using SL5 and CM's SL5 assembly but no joy...
Interestingly, if I try to use 'ActionMessage' elsewhere it seems to be resolved correctly but of course it's not very useful outside of where I want it!
Update:
This is the view namespace def
xmlns:cal="http://www.caliburnproject.org"
I've tried the actual assembly qualified namespace and other combinations, all with the same issue
I've never had to use the ActionMessage syntax before, but as long as the control has an event that you're trying to attach to have you tried the following syntax:
<Button Content="Remove" cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />
I've been able to use that on a wide variety of controls without any issues.
http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx
I had similar issues I had to add an extra xaml tag before calling ActionMessage my corresponding sample to get it to work was:
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<cal:Action.Target>
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs"/>
</cal:ActionMessage>
</cal:Action.Target>
</Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
</i:Interaction.Triggers>

Attach command with parameter to KeyUp event

I am currently transforming a medium size WPF project to MVVM and I ran into a problem that I wasn't able to solve, yet. Maybe you could help me out?
The target framework is .NET 3.5.1.
I have a list view that gets its items from the underlying view model. That view model is exposing a command to remove the selected items from the list view. Therefore the command parameter is bound to the SelectedItems property of the list view.
<ListView ItemsSource="{Binding MyItems}"
x:Name="MyListView"
SelectionMode="Extended">
</ListView>
<Button x:Name="MyRemoveButton"
Content="Remove item"
Command="{Binding RemoveItemCommand}"
CommandParameter="{Binding ElementName=MyListView, Path=SelectedItems}">
My intention is to execute this command not only when pressing a button, but also when the KeyUp event is fired on the list view and the pressed key is "delete".
I was close to finding the solution when I stumbled upon interaction triggers in this example:
http://joyfulwpf.blogspot.com/2009/05/mvvm-invoking-command-on-attached-event.html?showComment=1250325648481#c3867495357686026904
Now the problem with this demo is that the command parameter is the pressed key, but in my case I need the command parameter to be the SelectedItems property and I need the command to execute only on a specific key.
Is there any way to do this without much overhead and in the MVVM way?
Something like this would be awesome:
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<local:CommandAction Command="{Binding RemoveItemCommand}"
CommandParameter={Binding ElementName=MyListView, Path=SelectedItems}
EventArgument="Key.Delete"/>
</i:EventTrigger>
</i:Interaction.Triggers>
To do it in the MVVM way you need to bind "SelectedItems" property of the ListView to your ViewModel, so you could use it from your commands and wouldn't need to pass it via CommandParameter.
How strict is your separation requirement? If you don't have designers using Blend, then put a call to a ViewModel method into the KeyUp or PreviewKeyUp event handler in your code-behind.

Categories

Resources