Binding a function to the MouseDown event in xaml? - c#

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>

Related

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

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.

WP8 Databind button click/Command with RoutedEventHandler

Fairly new to Windows Phone and Xaml and I decided to start using the DataTemplates as it looked neater and I could easily switch them etc.
I have a requirement where on a button click depending on the data on the item in the list I want to call a different function or with different parameters. I thought the easiest way would be to bind a RoutedEventHandler to it via an anonymous function.
When I did this in code-behind with static controls on the formed it worked perfectly. It also worked when I added my own controls to a stack panel etc. But it was all quite messy.
// Example of RoutedEventHandler that works when I create the button in code behind
model.clickEventHandler = (s, e) => LoadResult(r.id);
<ScrollViewer Name="scrvResults" >
<ListBox Name="lbResults" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Command="{Binding clickEventHandler}" >
// Stuff
// Doesn't crash but doesn't fire the event
</Button>
<Button Click="{Binding clickEventHandler}" >
// Stuff
// Throws a com exception
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
I've tried various sub options. All the examples i've seen seem to link to a static function. Is this just some syntax i'm getting wrong is can I not bind to it this way?
You need to bind your command to a type of ICommand. See here for more info:
ICommand interface
Command Binding
Button click event can be bound by using interaction triggers, not by simply binding the event to the click attribute:
Using EventTrigger in XAML for MVVM – No Code Behind Code

Binding to XAML resource

I am creating a page-based WPF application using MVVM. I have created a custom (non dependency object) helper class to centralize navigation. This class is created as a resource of my main window like so.
<Window.Resources>
<local:NavigationManager x:Key="NavigationManagerKey" x:Name="NavigationManager"/>
</Window.Resources>
The class contains an ICommand that I have exposed publicly so that it can be used in XAML. However, I am struggling to find out how to bind to it. I would prefer not to have to set it as the data context for the page as that is already in use. Normally, I bind to a command like so (when I am binding to a command on the data context)
<Button Header="Image" Command="{Binding CreateImageAssetCommand}"></Button>
Thanks for any help with the matter.
You can set the source of the binding:
<Button Header="Image" Command="{Binding CreateImageAssetCommand, Source={StaticResource NavigationManagerKey}}"></Button>

Custom control toolbar need to invoke methods on my VM. How to do that?

Here is my question. I have UserControl that wraps group of buttons and it looks like this: (I show 2 buttons to illustrate what it is)
<Button Content="Cancel"
IsEnabled="{Binding State, Converter={StaticResource CancelEnabledConverter}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="Cancel" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Content="Delete"
IsEnabled="{Binding State, Converter={StaticResource DeleteEnabledConverter}}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="Delete" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Now, when I place this UserControl on my view - I go by convention and create Cancel and Delete methods on my VM. So, view's XAML looks clean.
I want to create custom control that will have same functionality. Inside control I will have to handle onClick events for buttons and would like to call methods on VM just like it works now. What my code going to look like? I guess I need to access DataContext programmatically and call method by name somehow. I envision using control like so:
<myToolBar Mode="SaveExitDelete" />
So, this will be nice and short. But myToolBar will show 3 buttons and those buttons will call 3 methods(named by convention) on DataContext.
Any pointers?
EDIT
Main question is to how programmaticaly BIND command or method to button. I understand how commanding works, I'm using PRISM and it's got built-in DelegateCommand that I can use. I don't know how to create binding programmaticaly when I know Method name or command name.
Here is how I can see it working:
var button = new DitatToolbarButton();
button.Caption = "Cancel &\nExit";
button.Icon = new BitmapImage(new Uri("img_btn_cancel.png", UriKind.Relative));
button.Command = Binding("CancelCommand");
Obviously 3rd line is wrong but this is what I want. I want to be able to hardcode string that will contain name of command that I will expect VM to have.
Typically, this sort of thing would be done with Commands. In the case of a Button control, which already has the "Command" DependencyProperty, it's as simple as this:
<Button Command="{Binding DoItCommand}">Do it</Button>
and in your view-model class:
private ICommand DoItCommand
{
get
{
return new DelegateCommand(param => DoIt(param), param => CanDoIt(param));
}
}
where DoIt() and CanDoIt() are methods in your view-model and DelegateCommand is defined something like this:
public class DelegateCommand : ICommand
{
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
// ...
There's a decent example of this here. On a custom control, you can declare the Command DependencyProperty yourself. And on a framework control that does not have a Command DependencyProperty, you can use an attached property.

Using a command on a custom control

I'm trying to use the search text box (which I made by following this tutorial: http://davidowens.wordpress.com/2009/02/18/wpf-search-text-box/).
I use MVVM & WPF. The above user control works when you write the "Search"-event in the code-behind file of the View, but I can't get it to work with a command (using the ViewModel).
(The search-event fires when you haven't typed something for about 2 seconds.)
I've tried using Caliburn, so it can "map" the view event to the viewmodel method. However when the event fires, the application crashes: "No target found for method SearchText()." on the RaiseSearchEvent method from the custom user control.
See the following test application: Test application
Could somebody tell me what I'm doing wrong? I told CaliBurn to do the following:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Search">
<cal:ActionMessage MethodName="SearchText()" />
</i:EventTrigger>
</i:Interaction.Triggers>
So I figure this is correct. It means that when the "Search" event fires, caliburn will look for the method SearchText in the ViewModel. This doesn't happen though, and it causes my app to crash and burn.
Do you know why? Or how I could solve this problem (doesn't have to be with Caliburn).
I already tried adding "Extending Command Support" (http://msdn.microsoft.com/en-us/library/dd458928.aspx), but this is a little too complex for me :/
Thanks for any help!!
You are using the Caliburn's ActionMessage but because you do not use its Bootstrapper class to start up your application, the MainView's DataContext is not set to an instance of the MainViewModel. If you check the SearchTextBox's DataContext at runtime, you'll see it's null.
Here's a series of steps that may solve your problem (using your linked example project)
Create a class called MyBootstrapper. It should look like this
public class MyBootstrapper : Bootstrapper<MainViewModel> {}
Add your new bootstrapper to the Application's Resources collection, like I show below (App.xaml)
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplicationParadise"
x:Class="WpfApplicationParadise.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:MyBootstrapper x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Not sure why, but if the bootstrapper isn't nested in my build, it never is instantiated when App.InitializeComponent() is run...
Change App.xaml.cs to simply run InitializeComponent. Note that I had to tweak your build a bit to get this to work... InitializeComponent() is only defined in the App.g.cs file if you have the nested resource dictionary from step 2, or if you have an x:Name attribute on App.xaml, or perhaps other things...
using System.Windows;
namespace WpfApplicationParadise
{
public partial class App : Application
{
public App()
{
InitializeComponent();
}
}
}
Finally, you need to remove the parens as Wallstreet Programmer suggested.
Those steps should cause your App to instantiate your bootstrapper, which in turn instantates the MainViewModel as the root viewmodel of your application, and then create a MainView and hook up its DataContext to the MainViewModel. At that point, your application should work as expected.
Remove ()
<cal:ActionMessage MethodName="SearchText" />
After I run your application, I see that you need to initialize the MainViewModel and also to bind Text of SearchTextBox with TekstBoxTekst.
Codebehind
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
this.Loaded += (s, e) =>
{
this.DataContext = new MainViewModel();
};
}
}
XAML
<StackPanel>
<l:SearchTextBox
Text="{Binding TekstBoxTekst, UpdateSourceTrigger=PropertyChanged}"
Height="24" x:Name="TekstBoxTekst" Margin="145,144,145,143">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Search">
<cal:ActionMessage MethodName="SearchText">
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</l:SearchTextBox>
</StackPanel>

Categories

Resources