In my WPF MVVM project application, click event command (AddUserCmd) is not get firing. Can you please find out the issue from my code part?
User.xaml
<Window x:Class="JP.User"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="User" WindowStartupLocation="CenterScreen"
Width="795" Height="500">
...
...
<TextBox Canvas.Left="114" TextWrapping="Wrap" Canvas.Top="98" RenderTransformOrigin="-0.093,-0.274" Width="157" Height="20" Background="{x:Null}" Foreground="#FF6B6C6C" Text="{Binding Path=Name}">
<TextBox Canvas.Left="114" TextWrapping="Wrap" Canvas.Top="129" RenderTransformOrigin="-0.093,-0.274" Width="157" Height="21" Background="{x:Null}" Foreground="#FF6B6C6C" Text="{Binding Path=Pwd}">
...
...
<Button Content="Save" Height="23" Name="button2" Width="75" Margin="605,0,0,0" Command="{Binding AddUserCmd}"/>
...
...
</Window>
UserViewModel.cs
public class UserViewModel : INotifyPropertyChanged
{
#region Private Variables
//The Variables are meant to be readonly as we mustnot change the address of any of them by creating new instances.
//Problem with new istances is that since address changes the binding becomes invalid.
//Instantiate all the variables in the constructor.
private readonly JanathaPOS.Model.User _user;
private readonly ObservableCollection<JanathaPOS.Model.User> _users;
private readonly UserManager _userManager;
private readonly ICommand _addUserCmd;
//private readonly ICommand _deleteUserCmd;
#endregion
#region Constructors
/// <summary>
/// Instatiates all the readonly variables
/// </summary>
public UserViewModel()
{
_user = new JanathaPOS.Model.User();
_userManager = new UserManager();
_users = new ObservableCollection<Model.User>();
_addUserCmd = new RelayCommand(Add, CanAdd);
}
#endregion
#region Public Properties
/// <summary>
/// Gets or Sets User Name. Ready to be binded to UI.
/// Impelments INotifyPropertyChanged which enables the binded element to refresh itself whenever the value changes.
/// </summary>
public string Name
{
get
{
return _user.Name;
}
set
{
_user.Name = value;
OnPropertyChanged("Name");
}
}
/// <summary>
/// Gets or Sets User Password. Ready to be binded to UI.
/// Impelments INotifyPropertyChanged which enables the binded element to refresh itself whenever the value changes.
/// </summary>
public string Pwd
{
get
{
return _user.Pwd;
}
set
{
_user.Pwd = value;
OnPropertyChanged("Pwd");
}
}
/// <summary>
/// Gets the Users. Used to maintain the User List.
/// Since this observable collection it makes sure all changes will automatically reflect in UI
/// as it implements both CollectionChanged, PropertyChanged;
/// </summary>
public ObservableCollection<JanathaPOS.Model.User> Users
{
get
{
return _users;
}
}
#endregion
#region Command Properties
/// <summary>
/// Gets the AddPatientCommand. Used for Add patient Button Operations
/// </summary>
public ICommand AddUserCmd
{
get
{
return _addUserCmd;
}
}
#endregion
#region Commands
#region AddCommand
/// <summary>
/// Add operation of the AddUserCmd.
/// Operation that will be performormed on the control click.
/// </summary>
/// <param name="obj"></param>
public void Add(object obj)
{
//Always create a new instance of patient before adding.
//Otherwise we will endup sending the same instance that is binded, to the BL which will cause complications
var user = new JanathaPOS.Model.User { Id = "123", Name = Name, Pwd = Pwd };
//Add patient will be successfull only if the patient with same ID does not exist.
if (_userManager.Add(user))
{
Users.Add(user);
ResetUser();
MessageBox.Show("User add Successful!");
}
else
{
MessageBox.Show("User with this ID already exists!");
}
}
/// <summary>
/// CanAdd operation of the AddUserCmd.
/// Tells us if the control is to be enabled or disabled.
/// This method will be fired repeatedly as long as the view is open.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public bool CanAdd(object obj)
{
//Enable the Button only if the mandatory fields are filled
if (Name != string.Empty && Pwd != string.Empty)
return true;
return false;
}
#endregion
#endregion
#region Private Methods
/// <summary>
/// Resets the Patient properties which will in turn auto reset the UI aswell
/// </summary>
private void ResetUser()
{
//Id = string.Empty;
Name = string.Empty;
Pwd = string.Empty;
}
#endregion
#region INotifyPropertyChanged Members
/// <summary>
/// Event to which the view's controls will subscribe.
/// This will enable them to refresh themselves when the binded property changes provided you fire this event.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// When property is changed call this method to fire the PropertyChanged Event
/// </summary>
/// <param name="propertyName"></param>
public void OnPropertyChanged(string propertyName)
{
//Fire the PropertyChanged event in case somebody subscribed to it
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
RelayCommand.cs
public class RelayCommand: ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
Related
How to create DataGridTextColumn change event in WPF(MVVM)?
Thanks
You can bind a command to DataGrid's CellEditEnding event:
<DataGrid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="CellEditEnding">
<ec:EventToCommand PassEventArgsToCommand="True"
Command="{Binding ItemEditedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
And in your codebehind
private ICommand _ItemEditedCommand;
public ICommand ItemEditedCommand => _ItemEditedCommand ?? (_ItemEditedCommand = new RelayCommand<DataGridCellEditEndingEventArgs>(ItemEditedCommand_Execute));
private void ItemEditedCommand_Execute(object param)
{
var cell = param as DataGridCellEditEndingEventArgs;
// Examine cell column and row and act accordingly
}
You don't necessarily need to use EventToCommand you can just use whatever you normally use inside the event trigger.
EDIT:
Here is an implementation of RelayCommand and EventToCommand in case you're having problems finding them:
EventToCommand:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace MyProj.Helpers.Command
{
/// <summary>
/// This <see cref="T:System.Windows.Interactivity.TriggerAction`1" /> can be
/// used to bind any event on any FrameworkElement to an <see cref="ICommand" />.
/// Typically, this element is used in XAML to connect the attached element
/// to a command located in a ViewModel. This trigger can only be attached
/// to a FrameworkElement or a class deriving from FrameworkElement.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
////[ClassInfo(typeof(EventToCommand),
//// VersionString = "5.2.8",
//// DateString = "201504252130",
//// Description = "A Trigger used to bind any event to an ICommand.",
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
//// Email = "laurent#galasoft.ch")]
public class EventToCommand : TriggerAction<DependencyObject>
{
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) => OnCommandChanged(s as EventToCommand, e)));
/// <summary>
/// Identifies the <see cref="MustToggleIsEnabled" /> dependency property
/// </summary>
public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register(
"MustToggleIsEnabled",
typeof(bool),
typeof(EventToCommand),
new PropertyMetadata(
false,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
private object _commandParameterValue;
private bool? _mustToggleValue;
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get
{
return GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This property is here for compatibility
/// with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="CommandParameter" /> property.
/// </summary>
public object CommandParameterValue
{
get
{
return _commandParameterValue ?? CommandParameter;
}
set
{
_commandParameterValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. If this property
/// is false, the element will not be disabled when the command's
/// CanExecute method changes. This is a DependencyProperty.
/// </summary>
public bool MustToggleIsEnabled
{
get
{
return (bool)GetValue(MustToggleIsEnabledProperty);
}
set
{
SetValue(MustToggleIsEnabledProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. This property is here for
/// compatibility with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="MustToggleIsEnabled" /> property.
/// </summary>
public bool MustToggleIsEnabledValue
{
get
{
return _mustToggleValue == null
? MustToggleIsEnabled
: _mustToggleValue.Value;
}
set
{
_mustToggleValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Called when this trigger is attached to a FrameworkElement.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
EnableDisableElement();
}
#if SILVERLIGHT
private Control GetAssociatedObject()
{
return AssociatedObject as Control;
}
#else
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The FrameworkElement to which this trigger
/// is attached.</returns>
private FrameworkElement GetAssociatedObject()
{
return AssociatedObject as FrameworkElement;
}
#endif
/// <summary>
/// This method is here for compatibility
/// with the Silverlight 3 version.
/// </summary>
/// <returns>The command that must be executed when
/// this trigger is invoked.</returns>
private ICommand GetCommand()
{
return Command;
}
/// <summary>
/// Specifies whether the EventArgs of the event that triggered this
/// action should be passed to the bound RelayCommand. If this is true,
/// the command should accept arguments of the corresponding
/// type (for example RelayCommand<MouseButtonEventArgs>).
/// </summary>
public bool PassEventArgsToCommand
{
get;
set;
}
/// <summary>
/// Gets or sets a converter used to convert the EventArgs when using
/// <see cref="PassEventArgsToCommand"/>. If PassEventArgsToCommand is false,
/// this property is never used.
/// </summary>
public IEventArgsConverter EventArgsConverter
{
get;
set;
}
/// <summary>
/// The <see cref="EventArgsConverterParameter" /> dependency property's name.
/// </summary>
public const string EventArgsConverterParameterPropertyName = "EventArgsConverterParameter";
/// <summary>
/// Gets or sets a parameters for the converter used to convert the EventArgs when using
/// <see cref="PassEventArgsToCommand"/>. If PassEventArgsToCommand is false,
/// this property is never used. This is a dependency property.
/// </summary>
public object EventArgsConverterParameter
{
get
{
return GetValue(EventArgsConverterParameterProperty);
}
set
{
SetValue(EventArgsConverterParameterProperty, value);
}
}
/// <summary>
/// Identifies the <see cref="EventArgsConverterParameter" /> dependency property.
/// </summary>
public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register(
EventArgsConverterParameterPropertyName,
typeof(object),
typeof(EventToCommand),
new PropertyMetadata(null));
/// <summary>
/// The <see cref="AlwaysInvokeCommand" /> dependency property's name.
/// </summary>
public const string AlwaysInvokeCommandPropertyName = "AlwaysInvokeCommand";
/// <summary>
/// Gets or sets a value indicating if the command should be invoked even
/// if the attached control is disabled. This is a dependency property.
/// </summary>
public bool AlwaysInvokeCommand
{
get
{
return (bool)GetValue(AlwaysInvokeCommandProperty);
}
set
{
SetValue(AlwaysInvokeCommandProperty, value);
}
}
/// <summary>
/// Identifies the <see cref="AlwaysInvokeCommand" /> dependency property.
/// </summary>
public static readonly DependencyProperty AlwaysInvokeCommandProperty = DependencyProperty.Register(
AlwaysInvokeCommandPropertyName,
typeof(bool),
typeof(EventToCommand),
new PropertyMetadata(false));
/// <summary>
/// Provides a simple way to invoke this trigger programatically
/// without any EventArgs.
/// </summary>
public void Invoke()
{
Invoke(null);
}
/// <summary>
/// Executes the trigger.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
/// <param name="parameter">The EventArgs of the fired event.</param>
protected override void Invoke(object parameter)
{
if (AssociatedElementIsDisabled()
&& !AlwaysInvokeCommand)
{
return;
}
var command = GetCommand();
var commandParameter = CommandParameterValue;
if (commandParameter == null
&& PassEventArgsToCommand)
{
commandParameter = EventArgsConverter == null
? parameter
: EventArgsConverter.Convert(parameter, EventArgsConverterParameter);
}
if (command != null
&& command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}
}
private static void OnCommandChanged(
EventToCommand element,
DependencyPropertyChangedEventArgs e)
{
if (element == null)
{
return;
}
if (e.OldValue != null)
{
((ICommand)e.OldValue).CanExecuteChanged -= element.OnCommandCanExecuteChanged;
}
var command = (ICommand)e.NewValue;
if (command != null)
{
command.CanExecuteChanged += element.OnCommandCanExecuteChanged;
}
element.EnableDisableElement();
}
private bool AssociatedElementIsDisabled()
{
var element = GetAssociatedObject();
return AssociatedObject == null
|| (element != null
&& !element.IsEnabled);
}
private void EnableDisableElement()
{
var element = GetAssociatedObject();
if (element == null)
{
return;
}
var command = GetCommand();
if (MustToggleIsEnabledValue
&& command != null)
{
element.IsEnabled = command.CanExecute(CommandParameterValue);
}
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
{
EnableDisableElement();
}
}
/// <summary>
/// The definition of the converter used to convert an EventArgs
/// in the <see cref="EventToCommand"/> class, if the
/// <see cref="EventToCommand.PassEventArgsToCommand"/> property is true.
/// Set an instance of this class to the <see cref="EventToCommand.EventArgsConverter"/>
/// property of the EventToCommand instance.
/// </summary>
////[ClassInfo(typeof(EventToCommand))]
public interface IEventArgsConverter
{
/// <summary>
/// The method used to convert the EventArgs instance.
/// </summary>
/// <param name="value">An instance of EventArgs passed by the
/// event that the EventToCommand instance is handling.</param>
/// <param name="parameter">An optional parameter used for the conversion. Use
/// the <see cref="EventToCommand.EventArgsConverterParameter"/> property
/// to set this value. This may be null.</param>
/// <returns>The converted value.</returns>
object Convert(object value, object parameter);
}
}
RelayCommand:
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace MyProj.Helpers.Command
{
public class RelayCommand : ICommand
{
#region Properties
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
#endregion
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null) throw new ArgumentNullException(nameof(execute));
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members }
}
public class RelayCommand<T> : ICommand
{
#region Fields
readonly Action<T> _execute;
readonly Predicate<T> _canExecute;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
/// </summary>
/// <param name="execute">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
/// <remarks><seealso cref="CanExecute"/> will always return true.</remarks>
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
///<summary>
///Defines the method that determines whether the command can execute in its current state.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
///<returns>
///true if this command can be executed; otherwise, false.
///</returns>
public bool CanExecute(object parameter) => _canExecute?.Invoke((T)parameter) ?? true;
///<summary>
///Occurs when changes occur that affect whether or not the command should execute.
///</summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
///<summary>
///Defines the method to be called when the command is invoked.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion
}
}
I have read many posts on binding an ObservableCollection to a ListView from people with similar issues; however, I haven't found a solution for my usecase, yet.
In the following test application, I have a simple ListView and a Button. On startup, the ListView is initialized, i.e. 2 columns and 30 rows with values from 0-29 are created. Half of the 30 rows (i.e. 15 rows) are visible. To see the remaining 15 Items I have to scroll down using the Scrollbar.
The Button is binded to an Asynchronous Command using the AsynchronousCommand Class from this article. When the button is clicked (see Start_Click), random numbers are written into those 30 rows of the ListView. This is done in an endless loop of a separate Thread (see AsynchronousCommand).
Now, when I click on the button, I would expect all ListView Items to change to random values instantaneously. However, this is not what's happening. Instead, only those Items that are not visible (i.e. the 15 Items beyond the ScrollBar) are changing their values. Sometimes, none of the Items changes its value.
Here's the XAML:
<Window x:Class="ListViewTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="614">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="38*"/>
<ColumnDefinition Width="9*"/>
</Grid.ColumnDefinitions>
<ListView HorizontalAlignment="Left" ItemsSource="{Binding MyList}" Height="261" Margin="28,24,0,0" VerticalAlignment="Top" Width="454" Grid.ColumnSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Width="100" Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="325" Header="Data" DisplayMemberBinding="{Binding Data}" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Start" Command="{Binding StartCommand}" Grid.Column="1" HorizontalAlignment="Left" Margin="21.043,42,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
This is my Code (View's CodeBehind, ViewModel, Controller Logic, and Model):
/// <summary>
/// This is the CodeBehind of my View
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LayoutRoot.DataContext = new ViewModel();
}
}
/// <summary>
/// This is my ViewModel
/// </summary>
public class ViewModel : NotifyPropertyChanged
{
private ObservableCollection<Document> _myList;
private Logic _logic;
private AsynchronousCommand _startCommand;
public ViewModel()
{
_myList = new ObservableCollection<Document>();
_logic = new Logic(this);
_startCommand = new AsynchronousCommand(_logic.Start_Click, true);
}
public ObservableCollection<Document> MyList
{
get { return _myList; }
set
{
if (_myList != value)
{
_myList = value;
RaisePropertyChangedEvent("MyList");
}
}
}
public AsynchronousCommand StartCommand
{
get
{
return _startCommand;
}
set
{
_startCommand = value;
}
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// This is my Controller
/// </summary>
public class Logic
{
private ViewModel _viewModel;
private Random _rnd;
public Logic(ViewModel vm)
{
_viewModel = vm;
_rnd = new Random();
for (int i = 0; i < 30; i++)
{
Document newDocument = new Document("Name " + i.ToString(), "Data " + i.ToString());
_viewModel.MyList.Add(newDocument);
}
}
public void Start_Click(object obj)
{
while (true)
{
int idx = _rnd.Next(0, 29);
_viewModel.StartCommand.ReportProgress(() =>
{
_viewModel.MyList[idx].Name = "New Name";
_viewModel.MyList[idx].Data = "New Data";
});
System.Threading.Thread.Sleep(20);
}
}
}
/// <summary>
/// This is my Model
/// </summary>
public class Document
{
public string Name { get; set; }
public string Data { get; set; }
public Document(string name, string data)
{
Name = name;
Data = data;
}
}
And this is the Code for my AsynchronousCommand, taken from Dave Kerr's article on CodeProject:
/// <summary>
/// The ViewModelCommand class - an ICommand that can fire a function.
/// </summary>
public class Command : ICommand
{
/// <summary>
/// Initializes a new instance of the <see cref="Command"/> class.
/// </summary>
/// <param name="action">The action.</param>
/// <param name="canExecute">if set to <c>true</c> [can execute].</param>
public Command(Action action, bool canExecute = true)
{
// Set the action.
this.action = action;
this.canExecute = canExecute;
}
/// <summary>
/// Initializes a new instance of the <see cref="Command"/> class.
/// </summary>
/// <param name="parameterizedAction">The parameterized action.</param>
/// <param name="canExecute">if set to <c>true</c> [can execute].</param>
public Command(Action<object> parameterizedAction, bool canExecute = true)
{
// Set the action.
this.parameterizedAction = parameterizedAction;
this.canExecute = canExecute;
}
/// <summary>
/// Executes the command.
/// </summary>
/// <param name="param">The param.</param>
public virtual void DoExecute(object param)
{
// Invoke the executing command, allowing the command to be cancelled.
CancelCommandEventArgs args = new CancelCommandEventArgs() { Parameter = param, Cancel = false };
InvokeExecuting(args);
// If the event has been cancelled, bail now.
if (args.Cancel)
return;
// Call the action or the parameterized action, whichever has been set.
InvokeAction(param);
// Call the executed function.
InvokeExecuted(new CommandEventArgs() { Parameter = param });
}
protected void InvokeAction(object param)
{
Action theAction = action;
Action<object> theParameterizedAction = parameterizedAction;
if (theAction != null)
theAction();
else if (theParameterizedAction != null)
theParameterizedAction(param);
}
protected void InvokeExecuted(CommandEventArgs args)
{
CommandEventHandler executed = Executed;
// Call the executed event.
if (executed != null)
executed(this, args);
}
protected void InvokeExecuting(CancelCommandEventArgs args)
{
CancelCommandEventHandler executing = Executing;
// Call the executed event.
if (executing != null)
executing(this, args);
}
/// <summary>
/// The action (or parameterized action) that will be called when the command is invoked.
/// </summary>
protected Action action = null;
protected Action<object> parameterizedAction = null;
/// <summary>
/// Bool indicating whether the command can execute.
/// </summary>
private bool canExecute = false;
/// <summary>
/// Gets or sets a value indicating whether this instance can execute.
/// </summary>
/// <value>
/// <c>true</c> if this instance can execute; otherwise, <c>false</c>.
/// </value>
public bool CanExecute
{
get { return canExecute; }
set
{
if (canExecute != value)
{
canExecute = value;
EventHandler canExecuteChanged = CanExecuteChanged;
if (canExecuteChanged != null)
canExecuteChanged(this, EventArgs.Empty);
}
}
}
#region ICommand Members
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
/// <returns>
/// true if this command can be executed; otherwise, false.
/// </returns>
///
bool ICommand.CanExecute(object parameter)
{
return canExecute;
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
void ICommand.Execute(object parameter)
{
this.DoExecute(parameter);
}
#endregion
/// <summary>
/// Occurs when can execute is changed.
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// Occurs when the command is about to execute.
/// </summary>
public event CancelCommandEventHandler Executing;
/// <summary>
/// Occurs when the command executed.
/// </summary>
public event CommandEventHandler Executed;
}
/// <summary>
/// The CommandEventHandler delegate.
/// </summary>
public delegate void CommandEventHandler(object sender, CommandEventArgs args);
/// <summary>
/// The CancelCommandEvent delegate.
/// </summary>
public delegate void CancelCommandEventHandler(object sender, CancelCommandEventArgs args);
/// <summary>
/// CommandEventArgs - simply holds the command parameter.
/// </summary>
public class CommandEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the parameter.
/// </summary>
/// <value>The parameter.</value>
public object Parameter { get; set; }
}
/// <summary>
/// CancelCommandEventArgs - just like above but allows the event to
/// be cancelled.
/// </summary>
public class CancelCommandEventArgs : CommandEventArgs
{
/// <summary>
/// Gets or sets a value indicating whether this <see cref="CancelCommandEventArgs"/> command should be cancelled.
/// </summary>
/// <value><c>true</c> if cancel; otherwise, <c>false</c>.</value>
public bool Cancel { get; set; }
}
/// <summary>
/// The AsynchronousCommand is a Command that runs on a thread from the thread pool.
/// </summary>
public class AsynchronousCommand : Command, INotifyPropertyChanged
{
/// <summary>
/// Initializes a new instance of the <see cref="AsynchronousCommand"/> class.
/// </summary>
/// <param name="action">The action.</param>
/// <param name="canExecute">if set to <c>true</c> the command can execute.</param>
public AsynchronousCommand(Action action, bool canExecute = true)
: base(action, canExecute)
{
// Initialise the command.
Initialise();
}
/// <summary>
/// Initializes a new instance of the <see cref="AsynchronousCommand"/> class.
/// </summary>
/// <param name="parameterizedAction">The parameterized action.</param>
/// <param name="canExecute">if set to <c>true</c> [can execute].</param>
public AsynchronousCommand(Action<object> parameterizedAction, bool canExecute = true)
: base(parameterizedAction, canExecute)
{
// Initialise the command.
Initialise();
}
/// <summary>
/// Initialises this instance.
/// </summary>
private void Initialise()
{
// Construct the cancel command.
cancelCommand = new Command(
() =>
{
// Set the Is Cancellation Requested flag.
IsCancellationRequested = true;
}, true);
}
/// <summary>
/// Executes the command.
/// </summary>
/// <param name="param">The param.</param>
public override void DoExecute(object param)
{
// If we are already executing, do not continue.
if (IsExecuting)
return;
// Invoke the executing command, allowing the command to be cancelled.
CancelCommandEventArgs args = new CancelCommandEventArgs() { Parameter = param, Cancel = false };
InvokeExecuting(args);
// If the event has been cancelled, bail now.
if (args.Cancel)
return;
// We are executing.
IsExecuting = true;
// Store the calling dispatcher.
callingDispatcher = Dispatcher.CurrentDispatcher;
// Run the action on a new thread from the thread pool (this will therefore work in SL and WP7 as well).
ThreadPool.QueueUserWorkItem(
(state) =>
{
// Invoke the action.
InvokeAction(param);
// Fire the executed event and set the executing state.
ReportProgress(
() =>
{
// We are no longer executing.
IsExecuting = false;
// If we were cancelled, invoke the cancelled event - otherwise invoke executed.
if (IsCancellationRequested)
InvokeCancelled(new CommandEventArgs() { Parameter = param });
else
InvokeExecuted(new CommandEventArgs() { Parameter = param });
// We are no longer requesting cancellation.
IsCancellationRequested = false;
}
);
}
);
}
/// <summary>
/// Raises the property changed event.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
private void NotifyPropertyChanged(string propertyName)
{
// Store the event handler - in case it changes between
// the line to check it and the line to fire it.
PropertyChangedEventHandler propertyChanged = PropertyChanged;
// If the event has been subscribed to, fire it.
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Reports progress on the thread which invoked the command.
/// </summary>
/// <param name="action">The action.</param>
public void ReportProgress(Action action)
{
if (IsExecuting)
{
if (callingDispatcher.CheckAccess())
action();
else
callingDispatcher.BeginInvoke(((Action)(() => { action(); })));
}
}
/// <summary>
/// Cancels the command if requested.
/// </summary>
/// <returns>True if the command has been cancelled and we must return.</returns>
public bool CancelIfRequested()
{
// If we haven't requested cancellation, there's nothing to do.
if (IsCancellationRequested == false)
return false;
// We're done.
return true;
}
/// <summary>
/// Invokes the cancelled event.
/// </summary>
/// <param name="args">The <see cref="Apex.MVVM.CommandEventArgs"/> instance containing the event data.</param>
protected void InvokeCancelled(CommandEventArgs args)
{
CommandEventHandler cancelled = Cancelled;
// Call the cancelled event.
if (cancelled != null)
cancelled(this, args);
}
protected Dispatcher callingDispatcher;
/// <summary>
/// Flag indicating that the command is executing.
/// </summary>
private bool isExecuting = false;
/// <summary>
/// Flag indicated that cancellation has been requested.
/// </summary>
private bool isCancellationRequested;
/// <summary>
/// The cancel command.
/// </summary>
private Command cancelCommand;
/// <summary>
/// The property changed event.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Occurs when the command is cancelled.
/// </summary>
public event CommandEventHandler Cancelled;
/// <summary>
/// Gets or sets a value indicating whether this instance is executing.
/// </summary>
/// <value>
/// <c>true</c> if this instance is executing; otherwise, <c>false</c>.
/// </value>
public bool IsExecuting
{
get
{
return isExecuting;
}
set
{
if (isExecuting != value)
{
isExecuting = value;
NotifyPropertyChanged("IsExecuting");
}
}
}
/// <summary>
/// Gets or sets a value indicating whether this instance is cancellation requested.
/// </summary>
/// <value>
/// <c>true</c> if this instance is cancellation requested; otherwise, <c>false</c>.
/// </value>
public bool IsCancellationRequested
{
get
{
return isCancellationRequested;
}
set
{
if (isCancellationRequested != value)
{
isCancellationRequested = value;
NotifyPropertyChanged("IsCancellationRequested");
}
}
}
/// <summary>
/// Gets the cancel command.
/// </summary>
public Command CancelCommand
{
get { return cancelCommand; }
}
}
Your Document Class has to implement INotifyPropertyChanged Interface so the UI gets updated once your Properties change.
Why is it working when you scroll?
Because of Virtualization. Not visible entries have not been evualuated yet, so once they get evaluated they already receive the "New Value".
Here is your Document class that works:
/// <summary>
/// This is my Model
/// </summary>
public class Document : INotifyPropertyChanged
{
private string _name;
private string _data;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public string Data
{
get { return _data; }
set
{
_data = value;
OnPropertyChanged();
}
}
public Document(string name, string data)
{
Name = name;
Data = data;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Let's say we have a control (a Button). This button is just thrown inside a grid in the most laziest way possible. The Command property is already binded, and it pops a MessageBox. I want to write a second command for my Button, let's say when Mouse enters it's surface (MouseEnter). But I want to do it this way
<Button Command="{Binding MyClick}" MySecondCommand= "{Binding MouseHoovering}"
Margin="34,39,0,0">
I know that ICommandSource forces me to implement Command property. As it is already implemented by ButtonBase and exposed in my example. What shoud I do to make "MySecondCommand" possible ? Just to declare it as a dependency property is not enough! :)
add your project --> CommandBehaviorBinding.cs,CommandBehavior.cs
use like this
<Button Command="{Binding MyClickCommand}"
Margin="34,39,0,0" local:CommandBehavior.Event="MouseHoovering"
local:CommandBehavior.Command="{Binding MouseHooveringCommand}">
CommandBehaviorBinding.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Reflection;
using System.Windows;
namespace yournamespace
{
public class CommandBehaviorBinding : IDisposable
{
#region Properties
/// <summary>
/// Get the owner of the CommandBinding ex: a Button
/// This property can only be set from the BindEvent Method
/// </summary>
public DependencyObject Owner { get; private set; }
/// <summary>
/// The event name to hook up to
/// This property can only be set from the BindEvent Method
/// </summary>
public string EventName { get; private set; }
/// <summary>
/// The event info of the event
/// </summary>
public EventInfo Event { get; private set; }
/// <summary>
/// Gets the EventHandler for the binding with the event
/// </summary>
public Delegate EventHandler { get; private set; }
#region Execution
//stores the strategy of how to execute the event handler
IExecutionStrategy strategy;
/// <summary>
/// Gets or sets a CommandParameter
/// </summary>
public object CommandParameter { get; set; }
ICommand command;
/// <summary>
/// The command to execute when the specified event is raised
/// </summary>
public ICommand Command
{
get { return command; }
set
{
command = value;
//set the execution strategy to execute the command
strategy = new CommandExecutionStrategy { Behavior = this };
}
}
Action<object> action;
/// <summary>
/// Gets or sets the Action
/// </summary>
public Action<object> Action
{
get { return action; }
set
{
action = value;
// set the execution strategy to execute the action
strategy = new ActionExecutionStrategy { Behavior = this };
}
}
#endregion
#endregion
//Creates an EventHandler on runtime and registers that handler to the Event specified
public void BindEvent(DependencyObject owner, string eventName)
{
EventName = eventName;
Owner = owner;
Event = Owner.GetType().GetEvent(EventName, BindingFlags.Public | BindingFlags.Instance);
if (Event == null)
throw new InvalidOperationException(String.Format("Could not resolve event name {0}", EventName));
//Create an event handler for the event that will call the ExecuteCommand method
EventHandler = EventHandlerGenerator.CreateDelegate(
Event.EventHandlerType, typeof(CommandBehaviorBinding).GetMethod("Execute", BindingFlags.Public | BindingFlags.Instance), this);
//Register the handler to the Event
Event.AddEventHandler(Owner, EventHandler);
}
/// <summary>
/// Executes the strategy
/// </summary>
public void Execute()
{
strategy.Execute(CommandParameter);
}
#region IDisposable Members
bool disposed = false;
/// <summary>
/// Unregisters the EventHandler from the Event
/// </summary>
public void Dispose()
{
if (!disposed)
{
Event.RemoveEventHandler(Owner, EventHandler);
disposed = true;
}
}
#endregion
}
}
CommandBehavior.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace yournamespace
{
public class CommandBehavior
{
#region Behavior
/// <summary>
/// Behavior Attached Dependency Property
/// </summary>
private static readonly DependencyProperty BehaviorProperty =
DependencyProperty.RegisterAttached("Behavior", typeof(CommandBehaviorBinding), typeof(CommandBehavior),
new FrameworkPropertyMetadata((CommandBehaviorBinding)null));
/// <summary>
/// Gets the Behavior property.
/// </summary>
private static CommandBehaviorBinding GetBehavior(DependencyObject d)
{
return (CommandBehaviorBinding)d.GetValue(BehaviorProperty);
}
/// <summary>
/// Sets the Behavior property.
/// </summary>
private static void SetBehavior(DependencyObject d, CommandBehaviorBinding value)
{
d.SetValue(BehaviorProperty, value);
}
#endregion
#region Command
/// <summary>
/// Command Attached Dependency Property
/// </summary>
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(CommandBehavior),
new FrameworkPropertyMetadata((ICommand)null,
new PropertyChangedCallback(OnCommandChanged)));
/// <summary>
/// Gets the Command property.
/// </summary>
public static ICommand GetCommand(DependencyObject d)
{
return (ICommand)d.GetValue(CommandProperty);
}
/// <summary>
/// Sets the Command property.
/// </summary>
public static void SetCommand(DependencyObject d, ICommand value)
{
d.SetValue(CommandProperty, value);
}
/// <summary>
/// Handles changes to the Command property.
/// </summary>
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
binding.Command = (ICommand)e.NewValue;
}
#endregion
#region Action
/// <summary>
/// Action Attached Dependency Property
/// </summary>
public static readonly DependencyProperty ActionProperty =
DependencyProperty.RegisterAttached("Action", typeof(Action<object>), typeof(CommandBehavior),
new FrameworkPropertyMetadata((Action<object>)null,
new PropertyChangedCallback(OnActionChanged)));
/// <summary>
/// Gets the Action property.
/// </summary>
public static Action<object> GetAction(DependencyObject d)
{
return (Action<object>)d.GetValue(ActionProperty);
}
/// <summary>
/// Sets the Action property.
/// </summary>
public static void SetAction(DependencyObject d, Action<object> value)
{
d.SetValue(ActionProperty, value);
}
/// <summary>
/// Handles changes to the Action property.
/// </summary>
private static void OnActionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
binding.Action = (Action<object>)e.NewValue;
}
#endregion
#region CommandParameter
/// <summary>
/// CommandParameter Attached Dependency Property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(CommandBehavior),
new FrameworkPropertyMetadata((object)null,
new PropertyChangedCallback(OnCommandParameterChanged)));
/// <summary>
/// Gets the CommandParameter property.
/// </summary>
public static object GetCommandParameter(DependencyObject d)
{
return (object)d.GetValue(CommandParameterProperty);
}
/// <summary>
/// Sets the CommandParameter property.
/// </summary>
public static void SetCommandParameter(DependencyObject d, object value)
{
d.SetValue(CommandParameterProperty, value);
}
/// <summary>
/// Handles changes to the CommandParameter property.
/// </summary>
private static void OnCommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
binding.CommandParameter = e.NewValue;
}
#endregion
#region Event
/// <summary>
/// Event Attached Dependency Property
/// </summary>
public static readonly DependencyProperty EventProperty =
DependencyProperty.RegisterAttached("Event", typeof(string), typeof(CommandBehavior),
new FrameworkPropertyMetadata((string)String.Empty,
new PropertyChangedCallback(OnEventChanged)));
/// <summary>
/// Gets the Event property. This dependency property
/// indicates ....
/// </summary>
public static string GetEvent(DependencyObject d)
{
return (string)d.GetValue(EventProperty);
}
/// <summary>
/// Sets the Event property. This dependency property
/// indicates ....
/// </summary>
public static void SetEvent(DependencyObject d, string value)
{
d.SetValue(EventProperty, value);
}
/// <summary>
/// Handles changes to the Event property.
/// </summary>
private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CommandBehaviorBinding binding = FetchOrCreateBinding(d);
//check if the Event is set. If yes we need to rebind the Command to the new event and unregister the old one
if (binding.Event != null && binding.Owner != null)
binding.Dispose();
//bind the new event to the command
binding.BindEvent(d, e.NewValue.ToString());
}
#endregion
#region Helpers
//tries to get a CommandBehaviorBinding from the element. Creates a new instance if there is not one attached
private static CommandBehaviorBinding FetchOrCreateBinding(DependencyObject d)
{
CommandBehaviorBinding binding = CommandBehavior.GetBehavior(d);
if (binding == null)
{
binding = new CommandBehaviorBinding();
CommandBehavior.SetBehavior(d, binding);
}
return binding;
}
#endregion
}
}
The mainpage:
MainPage.xaml
<Canvas x:Name="LayoutRoot" Background="White">
</Canvas>
MainPage.xaml.cs
List<Usol> list = new List<Usol>();
for (int i = 0; i < 10; i++)
{
var element = new Usol();
list.Add(element);
Canvas.SetTop(element, i * 25);
LayoutRoot.Children.Add(list[i]);
}
foreach (var item in list)
{
item.context.name = "Varken";
}
A usercontrol
Usol.xaml
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding Name}" />
</Grid>
Usol.xaml.cs
public Context context;
public Usol()
{
InitializeComponent();
context = new Context();
this.DataContext = context;
}
A class
Context.cs
public class Context : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region Fields
/// <summary>
/// Field Declaration for the <see cref="Name"/>
/// </summary>
private string name;
#endregion
#region Properties
/// <summary>
/// Gets or Sets the Name
/// </summary>
public string Name
{
get { return name; }
set
{
if (this.name != value)
{
this.name = value;
OnPropertyChanged("Name");
}
}
}
#endregion
}
Situation
I have created this small test application to copy a problem I have in a bigger application. It works about the same way (not exactly, but close enough).
It adds several custom made usercontrols and each get a own instance of a datacontext class.
However, none of the properties are willing to update themselfs due to a empty PropertyChangedEventHandler.
Question
Why is public event PropertyChangedEventHandler PropertyChanged; always null?
Context.cs needs to implement INotifyPropertyChanged interface. Are you doing that?
Edit: Post your update.
I have generally seen this kind of problem when programmers create "two" instances of Model/ViewModel. While you attach one instance with View, it's always the other one that gets update (which ofcourse will have a null PropertyChanged subscribers). Thus, you must make sure that your view is using the same instance as being updated at other parts.
Hope my point is clear.
Your code is wrong,
OnPropertyChanged("Name"); <-- should update "name" not "Name"
You are firing event saying that "Name" is changed, but name of property is "name", C# and binding are case sensitive.
Change it to,
#region Fields
/// <summary>
/// Field Declaration for the <see cref="name"/>
/// </summary>
private string _Name;
#endregion
#region Properties
/// <summary>
/// Gets or Sets the name
/// </summary>
public string Name
{
get { return _Name; }
set
{
if (this._Name != value)
{
this._Name = value;
OnPropertyChanged("Name");
}
}
}
#endregion
From C# 6 on wards, please use nameof() keyword...
#region Fields
/// <summary>
/// Field Declaration for the <see cref="name"/>
/// </summary>
private string _Name;
#endregion
#region Properties
/// <summary>
/// Gets or Sets the name
/// </summary>
public string Name
{
get { return _Name; }
set
{
if (this._Name != value)
{
this._Name = value;
OnPropertyChanged(nameof(Name));
}
}
}
#endregion
How can I bind a MouseDoubleClick event of a DataGrid to a delegate command and get the selected item of that grid.? I want to do this in XAML file as I'm using Prism 2.0 and MVVM pattern.
Please look at attached properties, it will be helpful.
The below is the code that will help, i had seen this somewhere but don't remember the site or author's name thanks to him anyways.
/// <summary>
/// The static class the defines the attached command DP for exposing MouseDoubleClick
/// event as a command
/// </summary>
public static class CommandMouseDoubleClick
{
#region TheCommandToRun
/// <summary>
/// TheCommandToRun : The actual ICommand to run
/// </summary>
public static readonly DependencyProperty TheCommandToRunProperty =
DependencyProperty.RegisterAttached("TheCommandToRun", typeof(ICommand),
typeof(CommandMouseDoubleClick),
new FrameworkPropertyMetadata((ICommand)null));
/// <summary>
/// Gets the TheCommandToRun property.
/// </summary>
public static ICommand GetTheCommandToRun(DependencyObject d)
{
return (ICommand)d.GetValue(TheCommandToRunProperty);
}
/// <summary>
/// Sets the TheCommandToRun property.
/// </summary>
public static void SetTheCommandToRun(DependencyObject d, ICommand value)
{
d.SetValue(TheCommandToRunProperty, value);
}
#endregion
#region RoutedEventName
/// <summary>
/// RoutedEventName : The event that should actually execute the
/// ICommand
/// </summary>
public static readonly DependencyProperty RoutedEventNameProperty =
DependencyProperty.RegisterAttached("RoutedEventName", typeof(String),
typeof(CommandMouseDoubleClick),
new FrameworkPropertyMetadata((String)String.Empty,
new PropertyChangedCallback(OnRoutedEventNameChanged)));
/// <summary>
/// Gets the RoutedEventName property.
/// </summary>
public static String GetRoutedEventName(DependencyObject d)
{
return (String)d.GetValue(RoutedEventNameProperty);
}
/// <summary>
/// Sets the RoutedEventName property.
/// </summary>
public static void SetRoutedEventName(DependencyObject d, String value)
{
d.SetValue(RoutedEventNameProperty, value);
}
/// <summary>
/// Hooks up a Dynamically created EventHandler (by using the
/// <see cref="MouseDoubleClickEventHooker">MouseDoubleClickEventHooker</see> class) that when
/// run will run the associated ICommand
/// </summary>
private static void OnRoutedEventNameChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
String routedEvent = (String)e.NewValue;
//If the RoutedEvent string is not null, create a new
//dynamically created EventHandler that when run will execute
//the actual bound ICommand instance (usually in the ViewModel)
if (!String.IsNullOrEmpty(routedEvent))
{
MouseDoubleClickEventHooker eventHooker = new MouseDoubleClickEventHooker();
eventHooker.ObjectWithAttachedCommand = d;
EventInfo eventInfo = d.GetType().GetEvent(routedEvent,
BindingFlags.Public | BindingFlags.Instance);
//Hook up Dynamically created event handler
if (eventInfo != null)
{
eventInfo.AddEventHandler(d,
eventHooker.GetNewEventHandlerToRunCommand(eventInfo));
}
}
}
#endregion
}
/// <summary>
/// Contains the event that is hooked into the source RoutedEvent
/// that was specified to run the ICommand
/// </summary>
sealed class MouseDoubleClickEventHooker
{
#region Properties
/// <summary>
/// The DependencyObject, that holds a binding to the actual
/// ICommand to execute
/// </summary>
public DependencyObject ObjectWithAttachedCommand { get; set; }
#endregion
#region Public Methods
/// <summary>
/// Creates a Dynamic EventHandler that will be run the ICommand
/// when the user specified RoutedEvent fires
/// </summary>
/// <param name="eventInfo">The specified RoutedEvent EventInfo</param>
///<returns>An Delegate that points to a new EventHandler
/// that will be run the ICommand</returns>
public Delegate GetNewEventHandlerToRunCommand(EventInfo eventInfo)
{
Delegate del = null;
if (eventInfo == null)
throw new ArgumentNullException("eventInfo");
if (eventInfo.EventHandlerType == null)
throw new ArgumentException("EventHandlerType is null");
if (del == null)
del = Delegate.CreateDelegate(eventInfo.EventHandlerType, this,
GetType().GetMethod("OnEventRaised",
BindingFlags.NonPublic |
BindingFlags.Instance));
return del;
}
#endregion
#region Private Methods
/// <summary>
/// Runs the ICommand when the requested RoutedEvent fires
/// </summary>
private void OnEventRaised(object sender, EventArgs e)
{
ICommand command = (ICommand)(sender as DependencyObject).
GetValue(CommandMouseDoubleClick.TheCommandToRunProperty);
if (command != null)
{
command.Execute(null);
}
}
#endregion
}
The xaml could look something like below:
<Label local:CommandMouseLeftButtonDown.RoutedEventName="MouseLeftButtonDown"
local:CommandMouseLeftButtonDown.TheCommandToRun="{Binding Path=MouseDownCommand, RelativeSource={RelativeSource TemplatedParent}}"
local:CommandMouseDoubleClick.RoutedEventName="MouseDoubleClick"
local:CommandMouseDoubleClick.TheCommandToRun="{Binding Path=MouseDoubleClickCommand, RelativeSource={RelativeSource TemplatedParent}}"/>