I have a view model that provides a RelayCommand LoadImage.
Typically I would use a button and bind the command to this button.
However I would like to call the LoadImage command from view's codebehind (I need to do some view related stuff that must not be put into view model)
The one way I am aware is to create an event handler for the button, e.g. Button_Click.
In Button_Click I would cast DataContext to the corresponding ViewModel and use this instance to call (DataContext as MyViewModel).LoadImage.Execute(...)
This is odd as I need to know the view model.
What I am trying, is to bind LoadImage not to a button but to a resource in the view, so the Button_Click event just need to call FindResource with a given name and cast it to ICommand without the necessity to know the specific ViewModel.
Is this possible? The command itself is not static as it needs to know the context in what it is called.
You can make it by creating a behavior, which requires Prism referred in your project:
public class LoadImageBehavior : Behavior<Button>
{
public public static static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof (ICommand), typeof (LoadImageBehavior));
public ICommand Command
{
get { return (ICommand) GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Click += AssociatedObject_Click;
}
private void AssociatedObject_Click(object sender, RoutedEventArgs e)
{
//Logic...
if(Command != null && Command.CanExecute(null))
Command.Execute(null);
//Logic...
}
}
On Xaml:
<Button>
<i:Interaction.Behaviors>
<Behaviors:LoadImageBehavior Command="{Binding LoadImageCommand}"/>
</i:Interaction.Behaviors>
</Button>
Based on Bill Zhangs idea of behaviours I've created a generic version which is quite control agnostic and which allows to be reused.
The required assembly is
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
I've created a Trigger action that passes the execution along to an event handler:
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System;
namespace Misc
{
public class CommandWithEventAction : TriggerAction<UIElement>
{
public event Func<object, object> Execute;
public static DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandWithEventAction), null);
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
public static DependencyProperty ParameterProperty = DependencyProperty.Register("Parameter", typeof(object), typeof(CommandWithEventAction), null);
public object Parameter
{
get
{
return GetValue(ParameterProperty);
}
set
{
SetValue(ParameterProperty, value);
}
}
protected override void Invoke(object parameter)
{
var result = Execute(Parameter);
Command.Execute(result);
}
}
}
To avoid any logic in a custom behaviour this allows to hook up any event to an event callback followed by a command call.
XAML:
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<misc:CommandWithEventAction Command="{Binding LoadImageCommand}" Parameter="Custom data" Execute="CommandWithEventAction_OnExecute"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Execute
</Button>
This will pass the "Custom data" string boxed as object to a function called
CommandWithEventAction_OnExecute
its signature of Func<object,object> may use the parameter and need to return something that will then be boxed into object and passed to the LoadImageCommand
Related
I'm new to WPF. Currently, I want to allow my Add button to add item by using either single click or double click. However, when I try to double click, it ends up fire single click event twice. Code in XAML as below:
<Button.InputBindings>
<MouseBinding Command="{Binding Path=AddCommand}" CommandParameter="{Binding}" MouseAction="LeftClick" />
<MouseBinding Command="{Binding Path=AddCommand}" CommandParameter="{Binding}" MouseAction="LeftDoubleClick" />
I found solution online which is to use DispatcherTimer in order to solve the problem. I have inserted these in code behind:
private static DispatcherTimer myClickWaitTimer =
new DispatcherTimer(
new TimeSpan(0, 0, 0, 1),
DispatcherPriority.Background,
mouseWaitTimer_Tick,
Dispatcher.CurrentDispatcher);
private void btnAdd_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Stop the timer from ticking.
myClickWaitTimer.Stop();
// Handle Double Click Actions
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
myClickWaitTimer.Start();
}
private static void mouseWaitTimer_Tick(object sender, EventArgs e)
{
myClickWaitTimer.Stop();
// Handle Single Click Actions
}
So here comes my question. I've removed the MouseBinding in XAML and want to call for AddCommand in code behind but I'm having problem to do so due to the PrismEventAggregator. The AddCommand in .cs as below:
private void AddCommandExecute(Object commandArg)
{
// Broadcast Prism event for adding item
this.PrismEventAggregator.GetEvent<AddItemEvent>().Publish(
new AddItemPayload()
{
BlockType = this.BlockType
}
);
}
Hence would like to know how to call for the AddCommand (which is a Prism Event in .cs) in Code behind?
Note: The button is inside resource dictionary thus I failed to use the button name to call for the command.
You need to create a class which will subscribe to the event you are publishing and then execute the logic you want.
For example:
public class AddItemViewModel : INotifyPropertyChanged
{
private IEventAggregator _eventAggregator;
public AddItemViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<AddItemEvent>().Subscribe(AddItem);
}
private void AddItem(AddItemPayload payload)
{
// Your logic here
}
}
Then when you publish the event it will trigger the subscriber and execute.
Using Expression Blend SDK, you can create a Behavior that encapsulates all your custom logic. This behavior will offer two dependency properties for your command and its parameter, so you can easily create Bindings for them, exactly as you do this for your InputBindings.
Move your event handlers and DispatcherTimer logic into this behavior:
using System.Windows.Interactivity;
class ClickBehavior : Behavior<Button>
{
// a dependency property for the command
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand),
typeof(ClickBehavior), new PropertyMetadata(null));
// a dependency property for the command's parameter
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object),
typeof(ClickBehavior), new PropertyMetadata(null));
public ICommand Command
{
get { return (ICommand)this.GetValue(CommandProperty); }
set { this.SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return this.GetValue(CommandParameterProperty); }
set { this.SetValue(CommandParameterProperty, value); }
}
// on attaching to a button, subscribe to its Click and MouseDoubleClick events
protected override void OnAttached()
{
this.AssociatedObject.Click += this.AssociatedObject_Click;
this.AssociatedObject.MouseDoubleClick += this.AssociatedObject_MouseDoubleClick;
}
// on detaching, unsubscribe to prevent memory leaks
protected override void OnDetaching()
{
this.AssociatedObject.Click -= this.AssociatedObject_Click;
this.AssociatedObject.MouseDoubleClick -= this.AssociatedObject_MouseDoubleClick;
}
// move your event handlers here
private void AssociatedObject_Click(object sender, RoutedEventArgs e)
{ //... }
private void AssociatedObject_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{ //... }
// call this method in your event handlers to execute the command
private void ExecuteCommand()
{
if (this.Command != null && this.Command.CanExecute(this.CommandParameter))
{
this.Command.Execute(this.CommandParameter);
}
}
The usage is very simple. You need to declare your additional namespaces:
<Window
xmlns:local="Your.Behavior.Namespace"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
...
Finally, attach the behavior to the button:
<Button>
<i:Interaction.Behaviors>
<local:ClickBehavior Command="{Binding AddCommand}" CommandParameter="{Binding}"/>
</i:Interaction.Behaviors>
</Button>
I have a dropdown (ComboBox) that displays all the com ports available on a machine. Now, ports come and go when you connect and disconnect devices.
For performance reasons I don't want to keep calling System.IO.Ports.SerialPort.GetPortNames(), but rather just call that when the user clicks on the Combobox? Is this possible? Is there an MVVM approach to this problem?
Use InvokeCommandAction.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
DropDownOpenedCommand is an ICommand property on your ViewModel.
<ComboBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="DropDownOpened">
<i:InvokeCommandAction Command="{Binding DropDownOpenedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
Edit: obviously DropDownOpened not SelectionChanged, as Patrice commented.
You can use something like MVVMLight's EventToCommand to accomplish this. Basically, the event of clicking the combo would be hooked to your MVVM command binding, which would then fire the method that calls GetPortNames().
Here are some alternatives:
MVVM Light: Adding EventToCommand in XAML without Blend, easier way or snippet? (check the accepted answer)
http://www.danharman.net/2011/08/05/binding-wpf-events-to-mvvm-viewmodel-commands/ (Prism)
What I would recommend is scrapping the 'only update on clicks' idea, and just use binding and notifications for this (unless for some reason you think there will be so many Connect/Disconnect events it will slow your system). The simplest version of that would be a dependency property.
Provide an IObservableList<Port> property as a dependency property on your ViewModel like this:
/// <summary>
/// Gets or sets...
/// </summary>
public IObservableList<Port> Ports
{
get { return (IObservableList<Port>)GetValue(PortsProperty); }
set { SetValue(PortsProperty, value); }
}
public static readonly DependencyProperty PortsProperty = DependencyProperty.Register("Ports", typeof(IObservableList<Port>), typeof(MyViewModelClass), new PropertyMetadata(new ObservableList<Port>));
Now you may add/remove items to/from that list whenever you connect or disconnect devices, just do not replace the list. This will force the list to send off a ListChangedEvent for each action on the list, and the ComboBox (or any other bound UI) will react to those events.
This should be performant enough for you, as this will only cause the UI ComboBox to update whenever an event goes through.
I took a stab at routing events to a command:
XAML:
<ComboBox
ItemsSource="{Binding Items}"
local:ControlBehavior.Event="SelectionChanged"
local:ControlBehavior.Command="{Binding Update}" />
Code:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
namespace StackOverflow
{
public class ControlBehavior
{
public static DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(ControlBehavior));
public static DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ControlBehavior));
public static DependencyProperty EventProperty = DependencyProperty.RegisterAttached("Event", typeof(string), typeof(ControlBehavior), new PropertyMetadata(PropertyChangedCallback));
public static void EventHandler(object sender, EventArgs e)
{
var s = (sender as DependencyObject);
if (s != null)
{
var c = (ICommand)s.GetValue(CommandProperty);
var p = s.GetValue(CommandParameterProperty);
if (c != null && c.CanExecute(s))
c.Execute(s);
}
}
public static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs a)
{
if (a.Property == EventProperty)
{
EventInfo ev = o.GetType().GetEvent((string)a.NewValue);
if (ev != null)
{
var del = Delegate.CreateDelegate(ev.EventHandlerType, typeof(ControlBehavior).GetMethod("EventHandler"));
ev.AddEventHandler(o, del);
}
}
}
public string GetEvent(UIElement element)
{
return (string)element.GetValue(EventProperty);
}
public static void SetEvent(UIElement element, string value)
{
element.SetValue(EventProperty, value);
}
public ICommand GetCommand(UIElement element)
{
return (ICommand)element.GetValue(CommandProperty);
}
public static void SetCommand(UIElement element, ICommand value)
{
element.SetValue(CommandProperty, value);
}
public object GetCommandParameter(UIElement element)
{
return element.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(UIElement element, object value)
{
element.SetValue(CommandParameterProperty, value);
}
}
}
Sorry to be cliche... but I'm pretty new to WPF and MVVM so I'm not sure how to handle this properly. I have a WinForms control within one of my views that I need to modify in it's code behind when an event is raised in the ViewModel. My view's datacontext is inherited so the viewmodel is not defined in the views constructor. How would I go about properly handling this? I am not using any frameworks with built in messengers or aggregators. My relevant code is below. I need to fire the ChangeUrl method from my ViewModel.
EDIT: Based on the suggestion from HighCore, I have updated my code. I am still not able to execute the ChangeUrl method however, the event is being raised in my ViewModel. What modifications need to be made??
UserControl.xaml
<UserControl ...>
<WindowsFormsHost>
<vlc:AxVLCPlugin2 x:Name="VlcPlayerObject" />
</WindowsFormsHost>
</UserControl>
UserControl.cs
public partial class VlcPlayer : UserControl
{
public VlcPlayer()
{
InitializeComponent();
}
public string VlcUrl
{
get { return (string)GetValue(VlcUrlProperty); }
set
{
ChangeVlcUrl(value);
SetValue(VlcUrlProperty, value);
}
}
public static readonly DependencyProperty VlcUrlProperty =
DependencyProperty.Register("VlcUrl", typeof(string), typeof(VlcPlayer), new PropertyMetadata(null));
private void ChangeVlcUrl(string newUrl)
{
//do stuff here
}
}
view.xaml
<wuc:VlcPlayer VlcUrl="{Binding Path=ScreenVlcUrl}" />
ViewModel
private string screenVlcUrl;
public string ScreenVlcUrl
{
get { return screenVlcUrl; }
set
{
screenVlcUrl = value;
RaisePropertyChangedEvent("ScreenVlcUrl");
}
}
WPF does not execute your property setter when you Bind the property, instead you must define a Callback method in the DependencyProperty declaration:
public string VlcUrl
{
get { return (string)GetValue(VlcUrlProperty); }
set { SetValue(VlcUrlProperty, value); }
}
public static readonly DependencyProperty VlcUrlProperty =
DependencyProperty.Register("VlcUrl", typeof(string), typeof(VlcPlayer), new PropertyMetadata(null, OnVlcUrlChanged));
private static void OnVlcUrlChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var player = obj as VlcPlayer;
if (obj == null)
return;
obj.ChangeVlcUrl(e.NewValue);
}
private void ChangeVlcUrl(string newUrl)
{
//do stuff here
}
I'm trying to pass the item on XamDataGrid on which I do a mouse right click to open a ContextMenu, which raises a Command in my ViewModel. Somehow the method that the Command calls is not reachable in debug mode.
This is the snipped from the view
<ig:XamDataGrid DataSource="{Binding DrdResults}" Height="700" Width="600">
<ig:XamDataGrid.ContextMenu>
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self},
Path=PlacementTarget.DataContext}"
AllowDrop="True" Name="cmAudit">
<MenuItem Header="View History"
Command="{Binding ViewTradeHistory}"
CommandParameter="{Binding Path=SelectedItems}">
</MenuItem>
</ContextMenu>
</ig:XamDataGrid.ContextMenu>
<ig:XamDataGrid.FieldSettings>
<ig:FieldSettings AllowFixing="NearOrFar"
AllowEdit="False"
Width="auto" Height="auto" />
</ig:XamDataGrid.FieldSettings>
</ig:XamDataGrid>
My code in the corresponding ViewModel for this View is as follows.
public WPF.ICommand ViewTradeHistory
{
get
{
if (_viewTradeHistory == null)
{
_viewTradeHistory = new DelegateCommand(
(object SelectedItems) =>
{
this.OpenTradeHistory(SelectedItems);
});
}
return _viewTradeHistory;
}
}
And lastly the actual method that gets called by the Command is as below
private void OpenTradeHistory(object records)
{
DataPresenterBase.SelectedItemHolder auditRecords
= (DataPresenterBase.SelectedItemHolder)records;
// Do something with the auditRecords now.
}
I'm not sure what am I doing incorrectly here. Any help will be very much appreciated.
Thanks,
Shravan
I had that working by improving Damian answer (which was not quite working).
Here's my solution:
First the Behaviour:
public class DataGridExtender : Behavior<XamDataGrid>
{
public readonly static DependencyProperty SelectedDataItemsProperty
= DependencyProperty.Register(
"SelectedDataItems",
typeof(ICollection<object>),
typeof(DataGridExtender),
new PropertyMetadata());
public ICollection<object> SelectedDataItems
{
get { return (ICollection<object>)GetValue(SelectedDataItemsProperty); }
set { SetValue(SelectedDataItemsProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItemsChanged += AssociatedObjectOnSelectedItemsChanged;
AssociatedObjectOnSelectedItemsChanged(AssociatedObject, null);
}
protected override void OnDetaching()
{
AssociatedObject.SelectedItemsChanged -= AssociatedObjectOnSelectedItemsChanged;
base.OnDetaching();
}
private void AssociatedObjectOnSelectedItemsChanged(object sender, Infragistics.Windows.DataPresenter.Events.SelectedItemsChangedEventArgs e)
{
if (SelectedDataItems != null)
{
SelectedDataItems.Clear();
foreach (var selectedDataItem in GetSelectedDataItems())
{
SelectedDataItems.Add(selectedDataItem);
}
}
}
private IEnumerable<object> GetSelectedDataItems()
{
var selectedItems = from rec in AssociatedObject.SelectedItems.Records.OfType<DataRecord>() select rec.DataItem;
return selectedItems.ToList().AsReadOnly();
}
}
And then its usage:
<igDP:XamDataGrid>
[...]
<i:Interaction.Behaviors>
<Behaviours:DataGridExtender SelectedDataItems="{Binding SelectedDataItems, Mode=TwoWay}"></Behaviours:DataGridExtender>
</i:Interaction.Behaviors>
[...]
<igDP:XamDataGrid.FieldLayoutSettings>
[...]
</igDP:XamDataGrid.FieldLayoutSettings>
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout>
[...]
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
Of course you'll need to have a "SelectedDataItems" in your view model.
Edit: The SelectedDataItems property in the view model has to be instantited first as an empty collection, otherwise it won't work.
For a single item, infragistics was kind enough to add a bindable DependencyProperty called 'ActiveDataItem', which is "the" selected item, if any.
It even works two-way, i.e. you can reset the selection from within your ViewModel.
Unfortunately, AFAIK there is no similar thing for multi-selection.
You will have to implement this on your own, iterating over the selected records, check if they are datarecords, get the record and dataitem etc...
Try binding your DataGrid's SelectedItem to a property in your viewmodel.
You can then access this property in your OpenTradeHistory() method.
For binding to the selected items I chose to create a behavior using System.Interactivity:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Interactivity;
using Infragistics.Windows.DataPresenter;
namespace Sample {
public class DataGridExtender : Behavior<XamDataGrid> {
public readonly static DependencyProperty SelectedDataItemsProperty
= DependencyProperty.Register(
"SelectedDataItems"
, typeof(ICollection<object>)
, typeof(OzDataGridExtender)
, new PropertyMetadata(null));
public ICollection<object> SelectedDataItems {
get { return (ICollection<object>)GetValue(SelectedDataItemsProperty); }
set { SetValue(SelectedDataItemsProperty, value); }
}
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.SelectedItemsChanged += AssociatedObjectOnSelectedItemsChanged;
AssociatedObjectOnSelectedItemsChanged(AssociatedObject, null);
}
protected override void OnDetaching() {
AssociatedObject.SelectedItemsChanged -= AssociatedObjectOnSelectedItemsChanged;
base.OnDetaching();
}
private void AssociatedObjectOnSelectedItemsChanged(object sender, Infragistics.Windows.DataPresenter.Events.SelectedItemsChangedEventArgs e) {
SelectedDataItems = GetSelectedDataItems();
//AssociatedObject.SetValue(SelectedDataItemsPropertyKey, SelectedDataItems);
}
private ICollection<object> GetSelectedDataItems() {
var selectedItems = from rec in AssociatedObject.SelectedItems.Records.OfType<DataRecord>()
select rec.DataItem;
return selectedItems.ToList().AsReadOnly();
}
}
}
Some where in your view would have something like the following (I've ommitted the namespace mappings for brevity):
Now your problem with the command binding on a context menu thats something else... I'll revisit this
What's a good method to bind Commands to Events? In my WPF app, there are events that I'd like to capture and process by my ViewModel but I'm not sure how. Things like losing focus, mouseover, mousemove, etc. Since I'm trying to adhere to the MVVM pattern, I'm wondering if there's a pure XAML solution.
Thanks!
Use System.Windows.Interactivity
…xmlns:i=http://schemas.microsoft.com/expression/2010/interactivity…
<Slider
<i:Interaction.Triggers>
<i:EventTrigger EventName="ValueChanged">
<i:InvokeCommandAction
Command="{Binding MyCommand}"
CommandParameter="{Binding Text, ElementName=textBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Slider>
Make sure your project references the assembly System.Windows.Interactivity.
Source: MSDN Blog Executing a command from an event of your choice
[Update]
Have a look to to Microsoft.Xaml.Behaviors.Wpf (available since 03.12.2018) Official package by Microsoft.
Have a look at Marlon Grech's Attached Command Behaviour, it could be exactly what you're looking for
In order to handle events, you must have some code that attaches itself to the event and executes your command in response. The final goal is to have in XAML:
MouseMoveCommand="{Binding MyCommand}"
In order to achieve this you need to define an attached property for each event that you want to handle. See this for an example and a framework for doing this.
I implemented it using Attached Properties and Reflection. I cannot say it is the best implementation, but I will maybe improve it and it may be a good start for you.
public class EventBinding : DependencyObject
{
public static string GetEventName(DependencyObject obj)
{
return (string)obj.GetValue(EventNameProperty);
}
public static void SetEventName(DependencyObject obj, string value)
{
obj.SetValue(EventNameProperty, value);
var eventInfo = obj.GetType().GetEvent(value);
var eventHandlerType = eventInfo.EventHandlerType;
var eventHandlerMethod = typeof(EventBinding).
GetMethod("EventHandlerMethod", BindingFlags.Static | BindingFlags.NonPublic);
var eventHandlerParameters = eventHandlerType.GetMethod("Invoke").GetParameters();
var eventArgsParameterType = eventHandlerParameters.
Where(p => typeof(EventArgs).IsAssignableFrom(p.ParameterType)).
Single().ParameterType;
eventHandlerMethod = eventHandlerMethod.MakeGenericMethod(eventArgsParameterType);
eventInfo.AddEventHandler(obj, Delegate.CreateDelegate(eventHandlerType, eventHandlerMethod));
}
private static void EventHandlerMethod<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs
{
var command = GetCommand(sender as DependencyObject);
command.Execute(new EventInfo<TEventArgs>(sender, e));
}
public static readonly DependencyProperty EventNameProperty =
DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventHandler));
public static ICommand GetCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventBinding));
}
public class EventInfo<TEventArgs>
{
public object Sender { get; set; }
public TEventArgs EventArgs { get; set; }
public EventInfo(object sender, TEventArgs e)
{
Sender = sender;
EventArgs = e;
}
}
public class EventInfo : EventInfo<EventArgs>
{
public EventInfo(object sender, EventArgs e)
: base(sender, e) { }
}
public class EventBindingCommand<TEventArgs> : RelayCommand<EventInfo<TEventArgs>>
where TEventArgs : EventArgs
{
public EventBindingCommand(EventHandler<TEventArgs> handler)
: base(info => handler(info.Sender, info.EventArgs)) { }
}
Examples of usage:
View
<DataGrid local:EventBinding.EventName="CellEditEnding"
local:EventBinding.Command="{Binding CellEditEndingCommand}" />
Model
private EventBindingCommand<DataGridCellEditEndingEventArgs> _cellEditEndingCommand;
public EventBindingCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand
{
get
{
return _cellEditEndingCommand ?? (
_cellEditEndingCommand = new EventBindingCommand<DataGridCellEditEndingEventArgs>(CellEditEndingHandler));
}
}
public void CellEditEndingHandler(object sender, DataGridCellEditEndingEventArgs e)
{
MessageBox.Show("Test");
}
I don't think you can use it in pure XAML, but take a look at the Delegate Command.
Execute Command, Navigate Frame, and Delegating Command behaviour is a pretty good pattern. It is also can be used in the Expression Blend.
On the "best practices" side, you should think twice before converting an event to a command. Normally, command is something user does intentionaly, an event most often is just an interaction trail, and should not leave the view boundaries.