Search code examples
c#mvvmmouseenter

How to write these particular lines in MVVM WPF(c#)?


.

   Console.WriteLine(DateTime.Now.ToLongTimeString());
            string name = (sender as Button).Name;

I have to convert these two lines to MVVM .The following is my code.

ViewModel.cs :

       public ICommand MouseEnterCommand
                {
                    get
                    {
                        return new RelayCommand(a => this.Executemethod(), p => Canexecutemethod());
                    }
                }
                public bool Canexecutemethod()
                {
                    return true;
                }

                public void Executemethod(){
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            string name = (sender as Button).Name;
switch(name)
            {
case "btn1":
...
case "btn2":
            ...
          }}

Where btn1 and btn2 are button names.....I have four buttons totally

View.xaml::

   <UserControl
    xmlns:interact="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    ..>
    <Grid>
    <Button Name="btn1">
    <interact:Interaction.Triggers>
    <interact:EventTrigger EventName="MouseEnter">
    <interact:InvokeCommandAction Command="{Binding  Path=DataContext.ZoomInCommand}" CommandParameter="{Binding }" />
    </interact:EventTrigger>
    </interact:Interaction.Triggers>
    </Button>
    </Grid>
    </UserControl>

Please help me to write these lines in MVVM..Thanks in advance


Solution

  • Here you will required EventToCommandBehavior which will transfer your event argument of Click event to viewModel. Like this:

    /// <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>
    {
        // Event
        public string Event
        {
            get { return ( string ) GetValue( EventProperty ); }
            set { SetValue( EventProperty, value ); }
        }
    
        public static readonly DependencyProperty EventProperty =
            DependencyProperty.Register( nameof( 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( nameof( 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( nameof( PassArguments ), typeof( bool ), typeof( EventToCommandBehavior ), new PropertyMetadata( false ) );
    
        protected override void OnAttached()
        {
            AttachHandler( Event ); // initial set
        }
    
        /// <summary>
        /// Attaches the handler to the event
        /// </summary>
        private void AttachHandler( string eventName )
        {
            // detach old event
            if ( oldEvent != null )
                oldEvent.RemoveEventHandler( AssociatedObject, handler );
    
            // attach new event
            if ( !string.IsNullOrEmpty( eventName ) )
            {
                EventInfo ei = AssociatedObject.GetType().GetEvent( eventName );
                if ( ei != null )
                {
                    MethodInfo mi = GetType().GetMethod( nameof( ExecuteCommand ), BindingFlags.Instance | BindingFlags.NonPublic );
                    if ( mi != null )
                    {
                        handler = Delegate.CreateDelegate( ei.EventHandlerType, this, mi );
                        ei.AddEventHandler( AssociatedObject, handler );
                        oldEvent = ei; // store to detach in case the Event property changes
                    }
                    else
                    {
                        throw new InvalidOperationException(
                            $"Method {nameof( ExecuteCommand )} not found in class {nameof( EventToCommandBehavior )}" );
                    }
                }
                else
                {
                    throw new ArgumentException( $"The event '{eventName}' was not found on type '{AssociatedObject.GetType().Name}'" );
                }
            }
        }
    
        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 );
        }
    
        /// <summary>
        /// Executes the Command
        /// </summary>
        // ReSharper disable once UnusedParameter.Local
        private void ExecuteCommand( object sender, EventArgs e )
        {
            object parameter = PassArguments ? e : null;
    
            if ( Command != null )
            {
                if ( Command.CanExecute( parameter ) )
                    Command.Execute( parameter );
            }
        }
    
        private Delegate handler;
        private EventInfo oldEvent;
    }
    

    Use this behavior in your xaml for button to pass RoutedEventArgs args to your command like this:

    <UserControl x:Class="YourNameSpace.YourClass">
    xmlns:beh="clr-namespace:YourNameSpace.Behaviors"
    ...
    <StackPanel Orientation="Horizontal" >
        <Button Margin="2" Content="Button 1" Name="btnButton1">
            <i:Interaction.Behaviors>
                <beh:EventToCommandBehavior Command="{Binding ButtonCommand}" Event="Click" PassArguments="True" />
            </i:Interaction.Behaviors>
        </Button>
        <Button Margin="2" Content="Button 2" Name="btnButton2">
            <i:Interaction.Behaviors>
                <beh:EventToCommandBehavior Command="{Binding ButtonCommand}" Event="Click" PassArguments="True" />
            </i:Interaction.Behaviors>
        </Button>
    
    </StackPanel>
    

    And Finally create RelayCommand like this

    public RelayCommand<RoutedEventArgs> ButtonCommand { get; }
    
    ButtonCommand = new RelayCommand<RoutedEventArgs>( x => Foo(x) );
    
    private void Foo( RoutedEventArgs args)
    {
        string buttonName = ( ( System.Windows.FrameworkElement )args.Source ).Name;
        //Your switch statements..
    }
    

    Likewise you can also attach more events like MouseEnter or MouseLeave