3

.

   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

Madhu
  • 101
  • 6

2 Answers2

0

I think, this one work for you

ViewModel.cs

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

    public bool Canexecutemethod(object a)
    {
        return true;
    }

    public void Executemethod(object p)
    {
        Console.WriteLine(DateTime.Now.ToLongTimeString());

        string name = Convert.ToString(p);

        switch (name)
        {
            default:
                break;
        }

    }
}

View.xaml::

<UserControl
    xmlns:interact="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    ..>
    <Grid>

            <Button Height="25" Width="150">
                <interact:Interaction.Triggers>
                    <interact:EventTrigger EventName="MouseEnter">
                    <interact:InvokeCommandAction Command="{Binding  MouseEnterCommand}" CommandParameter="MouseEnter" />
                    </interact:EventTrigger>
                </interact:Interaction.Triggers>
            </Button>

    </Grid>
</UserControl>
  • I have edited the switch condition in my question...Please help me to write that type of switch condition with button names as their case (in MVVM). @Saravanakumar Natarajan – Madhu Feb 06 '19 at 09:23
  • Thanks in Advance!! @Saravanakumar Natarajan – Madhu Feb 06 '19 at 09:24
  • @DSPT .You passed button name as CommandParameter="MouseEnter" in the UI and put a break point in the view model and check the value. – Saravanakumar Natarajan Feb 06 '19 at 09:35
  • No....For each button I should have both MouseEnter and MouseLeave events....Is it possible to do that in the way which u specified below? @Saravanakumar Natarajan – Madhu Feb 06 '19 at 09:42
  • My requirement is ...I should have four buttons and for each button I shoud have button name and two events namely MouseEnter and Mouse Leave....How to achieve this in MVVM....If you know please edit your answer accordingly...Thank you in advance! @Saravanakumar Natarajan – Madhu Feb 06 '19 at 09:57
  • @DSPT, Each button command parameter you need to mention the command Parameter then you will check work i guess – Saravanakumar Natarajan Feb 06 '19 at 10:02
0

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

Ankush Madankar
  • 3,689
  • 4
  • 40
  • 74
  • Thanks for the response ! @Ankush Madankar – Madhu Feb 07 '19 at 06:19
  • Is it possible to do this using InvokeCommandAction....Because your answer doesn't seems like it is in MVVM ....Is it in MVVM? ...I actually don't want to use "name=btn1" in view.xaml thats y. @Ankush Madankar – Madhu Feb 07 '19 at 06:21
  • @DSPT Yes this appoach is not fully MVVM since your ViewModel should not be knowing about view. But in your case you have single action/command to handle click opertaion from different button hence action identity required in VM. Either you need to create different (3) commands and bind to different button in UI. – Ankush Madankar Feb 07 '19 at 06:32
  • @DSPT Unfortunally you can not pass event argument in command with `InvokeCommandAction` see this post: https://stackoverflow.com/questions/6205472/mvvm-passing-eventargs-as-command-parameter. Hence I have create different behavior likewise to `InvokeCommandAction` with support of event argument. This will required to identify the action name from UI – Ankush Madankar Feb 07 '19 at 06:33
  • I'm totally confused now...Can anyone edit my code to meet my requirements....Someone please help me!! – Madhu Feb 07 '19 at 08:43
  • @DSPT Very specific to your question above solution should work. But as part of MVVM I would recommend you to create different `ICommand` for every button displayed on view which have create seperation between your view and vm and let few button events code in xaml.cs file. See this reference : https://stackoverflow.com/questions/6421372/why-to-avoid-the-codebehind-in-wpf-mvvm-pattern.. In short little code behind fine which has purely view's operations and not concern about business object. Let me know if you need further help!! – Ankush Madankar Feb 07 '19 at 11:13