WPF Simplifying OnPropertyChanged [duplicate] - wpf

I'm pretty new in WPF programming environment. I'm trying to write a program out using MVVM design pattern.
I've did some studies and read up some articles related to it and many of a time I came across this thing called
ViewModelBase
I know what it is.. But may I know specifically where should I begin with to be able to write out my own ViewModelBase? Like... Really understanding what's happening without getting too complicated. Thank you :)

It's worth nothing to use MVVM frameworks if you don't know what's going on inside.
So let's go step by step and build your own ViewModelBase class.
ViewModelBase is class common for all your viewmodels. Let's move all common logic to this class.
Your ViewModels should implement INotifyPropertyChanged (do you understand why?)
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
the [CallerMemberName] attribute is not required, but it will allow you to write:
OnPropertyChanged(); instead of OnPropertyChanged("SomeProperty");, so you will avoid string constant in your code. Example:
public string FirstName
{
set
{
_firstName = value;
OnPropertyChanged(); //instead of OnPropertyChanged("FirstName") or OnPropertyChanged(nameof(FirstName))
}
get{ return _firstName;}
}
Please note, that OnPropertyChanged(() => SomeProperty) is no more recommended, since we have nameof operator in C# 6.
It's common practice to implement properties that calls PropertyChanged like this:
public string FirstName
{
get { return _firstName; }
set { SetProperty(ref _firstName, value); }
}
Let's define SetProperty in your viewmodelbase:
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(storage, value))
return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
It simply fires PropertyChanged event when value of the property changes and returns true. It does not fire the event when the value has not changed and returns false. The basic idea is, that SetProperty method is virtual and you can extend it in more concrete class, e.g to trigger validation, or by calling PropertyChanging event.
This is pretty it. This is all your ViewModelBase should contain at this stage. The rest depends on your project. For example your app uses page base navigation and you have written your own NavigationService for handling navigation from ViewModel. So you can add NavigationService property to your ViewModelBase class, so you will have access to it from all your viewmodels, if you want.
In order to gain more reusability and keep SRP, I have class called BindableBase which is pretty much the implementation of INotifyPropertyChanged as we have done here. I reuse this class in every WPF/UWP/Silverligt/WindowsPhone solution because it's universal.
Then in each project I create custom ViewModelBase class derived from BindableBase:
public abstract ViewModelBase : BindableBase
{
//project specific logic for all viewmodels.
//E.g in this project I want to use EventAggregator heavily:
public virtual IEventAggregator () => ServiceLocator.GetInstance<IEventAggregator>()
}
if I have app, that uses page based navigation I also specify base class for page viewmodels.
public abstract PageViewModelBase : ViewModelBase
{
//for example all my pages have title:
public string Title {get; private set;}
}
I could have another class for dialogs:
public abstract DialogViewModelBase : ViewModelBase
{
private bool? _dialogResult;
public event EventHandler Closing;
public string Title {get; private set;}
public ObservableCollection<DialogButton> DialogButtons { get; }
public bool? DialogResult
{
get { return _dialogResult; }
set { SetProperty(ref _dialogResult, value); }
}
public void Close()
{
Closing?.Invoke(this, EventArgs.Empty);
}
}

The below class can be used as a ViewModelBase in WPF projects:
public abstract class ViewModelBase : INotifyPropertyChanged
{
/// <summary>
/// Multicast event for property change notifications.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Checks if a property already matches the desired value. Sets the property and
/// notifies listeners only when necessary.
/// </summary>
/// <typeparam name="T">Type of the property.</typeparam>
/// <param name="storage">Reference to a property with both getter and setter.</param>
/// <param name="value">Desired value for the property.</param>
/// <param name="propertyName">Name of the property used to notify listeners.This
/// value is optional and can be provided automatically when invoked from compilers that
/// support CallerMemberName.</param>
/// <returns>True if the value was changed, false if the existing value matched the
/// desired value.</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
// Log.DebugFormat("{0}.{1} = {2}", this.GetType().Name, propertyName, storage);
this.OnPropertyChanged(propertyName);
return true;
}
/// <summary>
/// Notifies listeners that a property value has changed.
/// </summary>
/// <param name="propertyName">Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers
/// that support <see cref="CallerMemberNameAttribute"/>.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
And an example of ViewModel class is:
public class MyViewModel : ViewModelBase
{
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set { SetProperty(ref myProperty, value); }
}
}
For ease of writing, below snippet can be used:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>OnPropertyChanged</Title>
</Header>
<Snippet>
<SnippetTypes>
<SnippetType>SurroundsWith</SnippetType>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Declarations>
<Literal>
<ID>TYPE</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>NAME1</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[private $TYPE$ _$NAME1$;
public $TYPE$ $NAME1$
{
get => _$NAME1$;
set => SetProperty(ref _$NAME1$, value);
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
The full code could be downloaded from here.

You have some nuget package to implement MVVM
MVVM light
MVVM Cross
Prism
For me the easier for a beginner is MVVM light because it provide some code sample.
So the better is to install this nuget package, have a look about the generated code and back to us for more explanations if you need.

In most MVVM frameworks, the base ViewModel classes actually contain very little code - usually just an implementation of INotifyPropertyChanged and some helper functions.
Take a look at the source code for MVVM Light's ViewModelBase and ObservableObject classes. ObservableObject is mostly the INotifyPropertyChanged implementation - using a lambda expression rather than "magic strings" for the property name. ViewModelBase extends ObservableObject and is mostly a utility method to determine if you're running inside the Visual Studio designer

I like this BaseVewModel it gives a nice clean style to your view models. Check out the various 'before' and 'after' comparisons. Of course, nothing is mandatory - if you don't like a feature that the BaseViewModel provides then don't use it. Or modify it because you have the source code. In particular note that there are three different ways to implement properties with change notification - choose the level of sophistication that you understand/feel comfortable with.

To revisit this answer today, I'd like to offer additional productivity improvements when writing MVVM code for Visual Studio.
The Intellisense in Visual Studio can automatically create the SetProperty boilerplate method. To do so, I set the ViewModel in the XAML of my Window (see below). Then, whenever I reference a {Binding Path=NewProperty}, Right Click and Select Quick Actions and Refactoring... (or via Ctrl .). If the SetProperty method isn't made, it will automatically be created for you within your ViewModel class. Further, it'll generate the property and field required for the Binding.
<Window x:Class="My.Project.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:My.Project"
mc:Ignorable="d"
xmlns:viewmodel="clr-namespace:My.Project.ViewModels" d:DataContext="{d:DesignInstance Type=viewmodel:MainWindowViewModel}"
Title="MainWindow" Height="360" Width="1000">
...
</Window>
However, this method has drawbacks
The INotifyPropertyChanged is not implemented and the OnPropertyChanged method is not implemented (if you need it)
This would need to be done in every ViewModel
This is specific for Visual Studio
Benefits:
Once the SetProperty method is defined in the project, using the Quick Actions and Refactoring... option will only generate the necessary property and field for you. This also works if you inherit from a ViewModelBase.
Here is the SetProperty method as generated by Visual Studio.
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
// Log.DebugFormat("{0}.{1} = {2}", this.GetType().Name, propertyName, storage);
this.OnPropertyChanged(propertyName);
return true;
}

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using System.Runtime.CompilerServices;
using System.ComponentModel;
namespace CollectionViewMVVM.ViewModel
{
public class BaseViewModel : INotifyPropertyChanged
{
/*Referencia: https://www.youtube.com/watch?v=PXEt1esjnZ0&ab_channel=Codigo369*/
public INavigation Navigation;
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnpropertyChanged([CallerMemberName] string nombre = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nombre));
}
private ImageSource foto;
public ImageSource Foto
{
get { return foto; }
set
{
foto = value;
OnpropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public async Task DisplayAlert(string title, string message, string cancel)
{
await Application.Current.MainPage.DisplayAlert(title, message, cancel);
}
public async Task<bool> DisplayAlert(string title, string message, string accept, string cancel)
{
return await Application.Current.MainPage.DisplayAlert(title, message, accept, cancel);
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if(EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
OnPropertyChanged(propertyName);
return true;
}
/*Ejemplo para declarar entrys*/
private string _title;
public string Title
{
get { return _title; }
set
{
SetProperty(ref _title, value);
}
}
/*Para tipos bool*/
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
SetProperty(ref _isBusy, value);
}
}
protected void SetValue<T>(ref T backingFielded, T value, [CallerMemberName] string propertyName = null)
{
if(EqualityComparer<T>.Default.Equals(backingFielded, value))
{
return;
}
backingFielded = value;
OnPropertyChanged(propertyName);
}
}
}

Related

Can't extend MVVMLight's ViewModelBase with INotifyPropertyChanged

I had been using my own ViewModelBase and RelayCommand, and recently I installed MVVMLight, as well as PropertyChanged.Fody. It appears that PropertyChanged.Fody doesn't notify if you're using a custom setter, so I do need to implement OnPropertyChanged somewhere myself.
public NotifiableViewModelBase CurrentViewModel
{
get => _currentViewModel;
set
{
// store the previous viewmodel when the viewmodel is changed.
PreviousViewModel = _currentViewModel;
_currentViewModel = value;
OnPropertyChanged();
}
}
This is a member of a class that still inherits from my own ViewModelBase
public abstract class NotifiableViewModelBase : INotifyPropertyChanged
{
protected NotifiableViewModelBase() { }
public virtual string DisplayName
{
get;
protected set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
I'd like to have this class inherit from MVVMLight's ViewModelBase, but if I do that, it says PropertyChanged hides its inherited member, and when I delete that event's declaration (to use the inherited member), I get errors in the OnPropertyChanged method, saying PropertyChanged can only be used on the left hand side of a += or -=.
I've managed to get around this by declaring PropertyChanged as a new event, which allows me to inherit from MVVMLight's ViewModelBase, but this smells improper to me.
Am I "doing it right" using the new event keywords, or is there some answer to how to use PropertyChanged as expected in the OnPropertyChanged?
(or, is there a way to write my custom setter and have the notification work without explicitly calling OnPropertyChanged()?)

Update View from ViewModel using Aspect Oriented Programming for read-only properties

I am using Aspect Oriented Programming in my WPF project. I have used it to decorate my viewModels with INotifyPropertyChanged interface and an implementation behavioral class as seen below:
Container.RegisterType<SomeViewModel>(
new Interceptor<VirtualMethodInterceptor>(),
new InterceptionBehavior(new LoggingBehavior(TraceEventType.Verbose)),
new AdditionalInterface<INotifyPropertyChanged>(),
new InterceptionBehavior<NotifyPropertyChangedBehavior>());
This works fine.
But when I have only get only properties like :
public bool IsDummy
{
get { return _isDummy; }
}
How do I call the OnPropertyChanged method from the ViewModel, which does the job of updating the View(UI). So if I update variable _isDummy to true, I should be able to call something which does the same job as OnPropertyChanged("IsDummY");
To notify the view that a value has changed you must raise the OnPropertyChanged event with the property which has changed. This is usually done by the standard implementation:
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Then in the setter of the property
public bool IsDummy
{
set
{
if (_isDummy!= value)
{
_isDummy= value;
OnPropertyChanged();
}
}
}
This syntax only works if it is called from within the property setter, alternatively you can call it when the property is changed elsewhere in the class
OnPropertyChanged(nameof(IsDummy));

Notify parent ViewModel of changes in child ViewModels

I have read a few articles on here, that describe how to listen to notifications raised. However: I am still having trouble to apply those to my application.
I currently have an application with several "pages".
One of the pages contains a WPF Treeview control in it along with several ViewModels and data models.
public class FoldersSearchViewModel
{
private ReadOnlyCollection<DriveTreeViewItemViewModel> _drives;
public FoldersSearchViewModel(string[] logicalDrives)
{
_drives = new ReadOnlyCollection<DriveTreeViewItemViewModel>(
Environment.GetLogicalDrives()
.Select(s => new DriveInfo(s))
.Where(di => di.IsReady)
.Select(di => new DriveTreeViewItemViewModel(di))
.ToList()
);
}
public ReadOnlyCollection<DriveTreeViewItemViewModel> Drives
{
get { return _drives; }
}
}
This ViewModel contains DriveTreeViewItemViewModels and is bound via DataContext to the UserControl ("page").
The Drive- and DirectoryTreeViewItemViewModel classes contain a few attributes, but are otherwise based on TreeViewItemViewModel, which you can see here:
public class TreeViewItemViewModel : INotifyPropertyChanged
{
#region Data
static readonly protected TreeViewItemViewModel DummyChild = new TreeViewItemViewModel();
readonly ObservableCollection<TreeViewItemViewModel> _children;
readonly TreeViewItemViewModel _parent;
bool _isExpanded;
bool _isSelected;
#endregion // Data
#region Constructors
protected TreeViewItemViewModel(TreeViewItemViewModel parent, bool lazyLoadChildren)
{
_parent = parent;
_children = new ObservableCollection<TreeViewItemViewModel>();
if (lazyLoadChildren)
_children.Add(DummyChild);
}
// This is used to create the DummyChild instance.
private TreeViewItemViewModel()
{
}
#endregion // Constructors
#region Presentation Members
#region Children
/// <summary>
/// Returns the logical child items of this object.
/// </summary>
public ObservableCollection<TreeViewItemViewModel> Children
{
get { return _children; }
}
#endregion // Children
#region HasLoadedChildren
/// <summary>
/// Returns true if this object's Children have not yet been populated.
/// </summary>
public bool HasDummyChild
{
get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
}
#endregion // HasLoadedChildren
#region IsExpanded
/// <summary>
/// Gets/sets whether the TreeViewItem
/// associated with this object is expanded.
/// </summary>
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (value != _isExpanded)
{
_isExpanded = value;
this.OnPropertyChanged("IsExpanded");
}
// Expand all the way up to the root.
if (_isExpanded && _parent != null)
_parent.IsExpanded = true;
// Lazy load the child items, if necessary.
if (this.HasDummyChild)
{
this.Children.Remove(DummyChild);
this.LoadChildren();
}
}
}
#endregion // IsExpanded
#region IsSelected
/// <summary>
/// Gets/sets whether the TreeViewItem
/// associated with this object is selected.
/// </summary>
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
}
#endregion // IsSelected
#region LoadChildren
/// <summary>
/// Invoked when the child items need to be loaded on demand.
/// Subclasses can override this to populate the Children collection.
/// </summary>
protected virtual void LoadChildren()
{
}
#endregion // LoadChildren
#region Parent
public TreeViewItemViewModel Parent
{
get { return _parent; }
}
#endregion // Parent
#endregion // Presentation Members
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion // INotifyPropertyChanged Members
}
I have followed the tutorial and ideas described in http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode and everything works great so far.
My problem is: I would like to add a string "selected" as an attribute to FoldersSearchViewModel, which would contain the path of the selected child ViewModel. The DriveTreeViewItemViewModel and the DirectoryTreeViewItemViewModel each have a "Path" property, that contains the full path to the child.
So: once OnPropertyChanged("IsSelected") is called, I would like to notify FoldersSearchViewModel about it and have the method copy the Path-property from the selected TreeViewItemViewModel into the new "selected"(string) attribute.
I could achieve this by passing the FoldersSearchViewModel-object to the children and children's children etc. in the constructor - but is there no better way of doing this? I suppose I should hook the FoldersSearchViewModel to the PropertyChanged-event of every node and sub-node, but I would like to know what someone with experience in MVVM would do in such a case.
By the way: I could use the WPF Treeview.SelectedItem to get the currently selected TreeViewItemViewModel, but that does not sound right since I want to keep the view, the models and the viewmodels separate.
P.s.: I tried reading and making use of MVVM in WPF - How to alert ViewModel of changes in Model... or should I?, but sadly it does not seem to solve my problem.
Any help is greatly appreciate!
The way mine works is, the Messenger service is a singleton as discussed. I also use DI, so a VM that needs to use it gets the IMessengerService instance injected into it.
IMessengerService looks like:
public interface IMessengerService : IServiceBase
{
Message<T> GetMessage<T>() where T : IMessageBase;
}
Message "param" classes are available application wide, so you might have something like:
public class FolderOpened : IMessageBase
{
}
So, the FolderOpened class is available throughout the application, its defined at compile time obviously.
Any client that would care about this message will subscribe to the message in its VM constructor:
_messenger.GetMessage().Handler += ...
It doesn't matter if the sender has "registered" it yet, the messenger is just based on the message class type.
At any time, anybody can send the message:
_messenger.GetMessage().SendMessage(...);
YMMV, but my messenger will automatically disconnect disposed / non existant subscribers, but really, the correct way would be for a VM to unsubscribe in its finalizer or dispose method.
Does that clear it up?
The MVVM way to do it would be to use a messenger / event aggregator pattern and broadcast an event.

How can I trigger the PropertyChanged event from static method?

I have the following class
public class LanguagingBindingSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Dummy
{
get { return String.Empty; }
set
{
PropertyChanged(this, new PropertyChangedEventArgs("Dummy"));
}
}
}
that is bound to elements in XAML like this
Text="{Binding Dummy,Source={StaticResource languageSource},Converter={StaticResource languageConverter},ConverterParameter=labelColor}"
The sole purpose of the LanguageBindingSource class and its Dummy method is to allow property notifications to update the bindings when one or more resources change. The actual bound values are provided by the converter, looking up resources by the names passed as parameters. See the comments on this answer for more background.
My problem is that the resources are changed by a process external to the XAML pages containing the bindings and I need a single static method that I can call to trigger property change notification for all instances of the binding. I'm struggling to figure out just how I might do that. All ideas will be most appreciated.
Modify your class as follows:-
public class LanguagingBindingSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate {};
public static void FirePropertyChanged(string key)
{
((LanguagingBindingSource)Application.Resources[key]).NotifyPropertyChanged("Dummy");
}
private void NotifyPropertyChanged(string name)
{
PropertyChanged(this, new PropertyChangedEventArgs(name);
}
public string Dummy
{
get { return String.Empty; }
set
{
NotifyPropertyChanged("Dummy"));
}
}
}
Now are any point where you need to fire off this change use:-
LanguagingBindingSource.FirePropertyChanged("languageBindingSource");
Where "languageBindingSource" is the resource key that you are also using in your binding Source property.

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;
}

Resources