WPF DataTemplate Event binding to object function
I'm currently writing DataTemplate for my custom type lets say FootballPlayer. In this template I would like to put ie. Button and make that button when clicked call some of FootballPlayer functions eg. Run().
Is there any simple or complex, but clean way to achieve this kind of behaviour?
The DataTemplate I believe is aware of all the information about my object because DataType is set and clr-namespace is included.
<DataTemplate DataType="{x:Type my:FootballPlayer}">
</DataTemplate>
I suppose there is a clean way to achieve this. Can anyone tell me how?
//edit The solution doesn't have开发者_如何转开发 to be clean. Now, after some investigation I'm just looking for any solution that can make a call to function / raise an event on the object being bound.
Yes, there is a clean way to do this. One aspect of using the Model-View-ViewModel pattern in WPF (not that you have to use this) is commanding. WPF Commanding reference
Here is a simplistic but clean and fairly type-safe framework class for exposing commands from your data source object:
using System;
using System.Windows.Input;
namespace MVVM
{
/// <summary>
/// Defines a command that can be bound to from XAML and redirects to a handler function.
/// </summary>
public class ViewModelCommand : ICommand
{
private Action _handler;
public ViewModelCommand(Action handler)
{
_handler = handler;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
#endregion
}
/// <summary>
/// Defines a command that can be bound to from XAML and redirects to a handler function.
/// </summary>
public class ViewModelCommand<T> : ICommand
where T : class
{
private Action<T> _handler;
public ViewModelCommand(Action<T> handler)
{
_handler = handler;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler(parameter as T);
}
#endregion
}
}
Your data source (e.g., FootballPlayer class) then exposes a command property as follows:
/// <summary>
/// Tell the player to run. This particular command takes a string as a parameter.
/// </summary>
public ICommand RunCommand
{
get { return new ViewModelCommand<string>(run); }
}
The implementation function, in the same FootballPlayer class, can then look like this:
/// <summary>
/// Tell the player to run. This particular command takes a string as a parameter.
/// </summary>
public void search(string destination)
{
System.Windows.MessageBox.Show(destination, "Running to destination...");
}
Finally, your XAML has the following databinding:
<Button Content="{Binding PlayerName}" FontSize="16" CommandParameter="{Binding Text, ElementName=txtDestination}" Command="{Binding RunCommand, Source={StaticResource ViewModelDataSource}}" />
(Since you're using a DataTemplate, the sources of the bindings would need to be adjusted; but that's the gist of it. I've used this with great success in a class project - it allowed a very clean separation between the logic and the UI.)
If you set up a generic handler for the event:
<Button Click="FootballPlayer_Run"/>
the DataContext of the e.OriginalSource will be the FootballPlayer object that is used for binding. You can then call Run on that object.
private void FootballPlayer_Run(object sender, RoutedEventArgs e)
{
FrameworkElement ele = e.OriginalSource as FrameworkElement;
if (ele != null)
{
FootballPlayer fp = ele.DataContext as FootballPlayer;
if (fp != null)
{
fp.Run();
}
}
e.Handled = true;
}
精彩评论