Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Passing EventArgs As Command Parameter

I'm using Microsoft Expression Blend 4
I have a Browser ..,

[ XAML ] ConnectionView " Empty Code Behind "

        <WebBrowser local:AttachedProperties.BrowserSource="{Binding Source}">             <i:Interaction.Triggers>                 <i:EventTrigger>                     <i:InvokeCommandAction Command="{Binding LoadedEvent}"/>                 </i:EventTrigger>                 <i:EventTrigger EventName="Navigated">                     <i:InvokeCommandAction Command="{Binding NavigatedEvent}" CommandParameter="??????"/>                 </i:EventTrigger>             </i:Interaction.Triggers>         </WebBrowser>   

[ C# ] AttachedProperties class

public static class AttachedProperties     {         public static readonly DependencyProperty BrowserSourceProperty = DependencyProperty . RegisterAttached ( "BrowserSource" , typeof ( string ) , typeof ( AttachedProperties ) , new UIPropertyMetadata ( null , BrowserSourcePropertyChanged ) );          public static string GetBrowserSource ( DependencyObject _DependencyObject )         {             return ( string ) _DependencyObject . GetValue ( BrowserSourceProperty );         }          public static void SetBrowserSource ( DependencyObject _DependencyObject , string Value )         {             _DependencyObject . SetValue ( BrowserSourceProperty , Value );         }          public static void BrowserSourcePropertyChanged ( DependencyObject _DependencyObject , DependencyPropertyChangedEventArgs _DependencyPropertyChangedEventArgs )         {             WebBrowser _WebBrowser = _DependencyObject as WebBrowser;             if ( _WebBrowser != null )             {                 string URL = _DependencyPropertyChangedEventArgs . NewValue as string;                 _WebBrowser . Source = URL != null ? new Uri ( URL ) : null;             }         }     } 

[ C# ] ConnectionViewModel Class

public class ConnectionViewModel : ViewModelBase     {             public string Source             {                 get { return Get<string> ( "Source" ); }                 set { Set ( "Source" , value ); }             }              public void Execute_ExitCommand ( )             {                 Application . Current . Shutdown ( );             }              public void Execute_LoadedEvent ( )             {                 MessageBox . Show ( "___Execute_LoadedEvent___" );                 Source = ...... ;             }              public void Execute_NavigatedEvent ( )             {                 MessageBox . Show ( "___Execute_NavigatedEvent___" );             }     } 

[ C# ] ViewModelBase class Here

Finally :
Binding with commands works well and MessageBoxes shown


My Question :
How to pass NavigationEventArgs as Command Parameters when Navigated Event occurs ?

like image 257
Ahmed Ghoneim Avatar asked Jun 01 '11 17:06

Ahmed Ghoneim


2 Answers

It's not easily supported. Here's an article with instructions on how to pass EventArgs as command parameters.

You might want to look into using MVVMLight - it supports EventArgs in command directly; your situation would look something like this:

 <i:Interaction.Triggers>     <i:EventTrigger EventName="Navigated">         <cmd:EventToCommand Command="{Binding NavigatedEvent}"             PassEventArgsToCommand="True" />     </i:EventTrigger>  </i:Interaction.Triggers> 
like image 102
E.Z. Hart Avatar answered Sep 28 '22 08:09

E.Z. Hart


I try to keep my dependencies to a minimum, so I implemented this myself instead of going with EventToCommand of MVVMLight. Works for me so far, but feedback is welcome.

Xaml:

<i:Interaction.Behaviors>     <beh:EventToCommandBehavior Command="{Binding DropCommand}" Event="Drop" PassArguments="True" /> </i:Interaction.Behaviors> 

ViewModel:

public ActionCommand<DragEventArgs> DropCommand { get; private set; }  this.DropCommand = new ActionCommand<DragEventArgs>(OnDrop);  private void OnDrop(DragEventArgs e) {     // ... } 

EventToCommandBehavior:

/// <summary> /// Behavior that will connect an UI event to a viewmodel Command, /// allowing the event arguments to be passed as the CommandParameter. /// </summary> public class EventToCommandBehavior : Behavior<FrameworkElement> {     private Delegate _handler;     private EventInfo _oldEvent;      // Event     public string Event { get { return (string)GetValue(EventProperty); } set { SetValue(EventProperty, value); } }     public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(string), typeof(EventToCommandBehavior), new PropertyMetadata(null, OnEventChanged));      // Command     public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }     public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommandBehavior), new PropertyMetadata(null));      // PassArguments (default: false)     public bool PassArguments { get { return (bool)GetValue(PassArgumentsProperty); } set { SetValue(PassArgumentsProperty, value); } }     public static readonly DependencyProperty PassArgumentsProperty = DependencyProperty.Register("PassArguments", typeof(bool), typeof(EventToCommandBehavior), new PropertyMetadata(false));       private static void OnEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)     {         var beh = (EventToCommandBehavior)d;          if (beh.AssociatedObject != null) // is not yet attached at initial load             beh.AttachHandler((string)e.NewValue);     }      protected override void OnAttached()     {         AttachHandler(this.Event); // initial set     }      /// <summary>     /// Attaches the handler to the event     /// </summary>     private void AttachHandler(string eventName)     {         // detach old event         if (_oldEvent != null)             _oldEvent.RemoveEventHandler(this.AssociatedObject, _handler);          // attach new event         if (!string.IsNullOrEmpty(eventName))         {             EventInfo ei = this.AssociatedObject.GetType().GetEvent(eventName);             if (ei != null)             {                 MethodInfo mi = this.GetType().GetMethod("ExecuteCommand", BindingFlags.Instance | BindingFlags.NonPublic);                 _handler = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);                 ei.AddEventHandler(this.AssociatedObject, _handler);                 _oldEvent = ei; // store to detach in case the Event property changes             }             else                 throw new ArgumentException(string.Format("The event '{0}' was not found on type '{1}'", eventName, this.AssociatedObject.GetType().Name));         }     }      /// <summary>     /// Executes the Command     /// </summary>     private void ExecuteCommand(object sender, EventArgs e)     {         object parameter = this.PassArguments ? e : null;         if (this.Command != null)         {             if (this.Command.CanExecute(parameter))                 this.Command.Execute(parameter);         }     } } 

ActionCommand:

public class ActionCommand<T> : ICommand {     public event EventHandler CanExecuteChanged;     private Action<T> _action;      public ActionCommand(Action<T> action)     {         _action = action;     }      public bool CanExecute(object parameter) { return true; }      public void Execute(object parameter)     {         if (_action != null)         {             var castParameter = (T)Convert.ChangeType(parameter, typeof(T));             _action(castParameter);         }     } } 
like image 40
Mike Fuchs Avatar answered Sep 28 '22 10:09

Mike Fuchs