Any WinRT iCommand/CommandBinding implementaiton samples out there?
Asked Answered
I

5

15

Abstracting commands into the View Model is a valuable practice with XAML/MVVM projects. I get that. And, I see ICommand in in WinRT; but, how do we implement it? I haven't found a sample that actually works. Anyone know?

Iceskate answered 14/8, 2012 at 20:48 Comment(1)
you should grow some patience!Iceskate
E
20

My all time favorite has to be the DelegateCommand provided by the Microsoft Patterns and Practices team. It allows you to create a typed command:

MyCommand = new DelegateCommand<MyEntity>(OnExecute);
...
private void OnExecute(MyEntity entity)
{...}

It also provides a way to raise the CanExecuteChanged event (to disable/enable the command)

MyCommand.RaiseCanExecuteChanged();

Here's the code:

public class DelegateCommand<T> : ICommand
{
    private readonly Func<T, bool> _canExecuteMethod;
    private readonly Action<T> _executeMethod;

    #region Constructors

    public DelegateCommand(Action<T> executeMethod)
        : this(executeMethod, null)
    {
    }

    public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
    {
        _executeMethod = executeMethod;
        _canExecuteMethod = canExecuteMethod;
    }

    #endregion Constructors

    #region ICommand Members

    public event EventHandler CanExecuteChanged;

    bool ICommand.CanExecute(object parameter)
    {
        try
        {
            return CanExecute((T)parameter);
        }
        catch { return false; }
    }

    void ICommand.Execute(object parameter)
    {
        Execute((T)parameter);
    }

    #endregion ICommand Members

    #region Public Methods

    public bool CanExecute(T parameter)
    {
        return ((_canExecuteMethod == null) || _canExecuteMethod(parameter));
    }

    public void Execute(T parameter)
    {
        if (_executeMethod != null)
        {
            _executeMethod(parameter);
        }
    }

    public void RaiseCanExecuteChanged()
    {
        OnCanExecuteChanged(EventArgs.Empty);
    }

    #endregion Public Methods

    #region Protected Methods

    protected virtual void OnCanExecuteChanged(EventArgs e)
    {
        var handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    #endregion Protected Methods
}
Eigenfunction answered 15/8, 2012 at 5:23 Comment(5)
I don't like the generic part (as default) but I like the sample!Iceskate
@JerryNixon-MSFT - why don't you "[not] like the generic part"? If you want to avoid the generic, you'd have to make the code more complicated by taking Action<object>, or Action<dynamic> and then performing all of the associated casting and type checking to get the same resultSanmiguel
@Shawn Kendrot - in ICommand.CanExecute, you could replace that potentially expensive try... catch block, couldn't you just do return CanExecute(parameter as T), then in CanExecute, add a check for parameter == null?Sanmiguel
nvm, forgot that you can't guarantee that T is a ref typeSanmiguel
You could also check the type with an implicit cast. The code makes an assumption that you will pass in the appropriate type b/c you know your Command and what it expects.Eigenfunction
C
3

Check out RelayCommand class (only METRO code). The NotifyPropertyChanged class can be found here. The NotifyPropertyChanged class is only used to allow bindings on CanExecute and update it with RaiseCanExecuteChanged.

The original relay command class can be found here

Crosscountry answered 14/8, 2012 at 23:14 Comment(0)
C
2

Unfortunately there does not seem to be a native class that implements it for you. The interface is not overly complicated if you want to implement it yourself, and the popular MVVM Lite toolkit includes its own version of RelayCommand. You can add MVVM Lite to your project by right-clicking on References and choosing "Manage NuGet Packages". If you don't have this option, enable Nuget under Tools -> Extensions and Updates.

Cropdusting answered 15/8, 2012 at 2:24 Comment(0)
G
0

I've been looking for a minimal end-to-end implementation of a XAML-MVVM command, and not found it yet.

So, following #Rico's answer I ended up with the following as a minimal RelayCommand which works. I use a similar minimal version in a large project.

public class RelayCommand : System.Windows.Input.ICommand {

    readonly Action<object> execute; 

    public RelayCommand(Action<object> execute) {
        this.execute = execute;
    }

    public bool CanExecute(object parameter) {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter) {
        this.execute(parameter);
    }
}

The larger RelayCommand class seems to provide more control over CanExecute and CanExecuteChanged, but you don't need that to get started - and you may not need it at all.

To use it in a view model:

class ViewModel : INotifyPropertyChanged {

    << ... snip VM properties and notifications ...>>

    public RelayCommand DoSomethingCommand {
        get {
            return new RelayCommand(param => {
                this.DoSomething(param as AType);
                Debug.WriteLine("Command Executed");
            });
        }

    }
}

(We don't need the INotifyPropertyChanged for the Command, but any view model typically implements it.)

Finally, the XAML...

   <Grid>
        <!-- Set the data context here, for illustration. -->
        <Grid.DataContext>
            <local:ViewModel/>
        </Grid.DataContext>
        <!-- A sample control bind to a property -->
        <TextBlock 
             Text="{Binding AProp}"/>
        <!-- Bind a command -->
        <Button Command="{Binding DoSomethingCommand}" CommandParameter="foo">Change!</Button>
    </Grid>
Ghirlandaio answered 24/9, 2014 at 4:36 Comment(0)
T
0

I found this really good example at https://code.msdn.microsoft.com/windowsapps/Working-with-ICommand-690ba1d4

<Page.Resources> 
        <local:MyCommandsCollection x:Key="MyCommands" /> 
</Page.Resources> 

   <Button Width="280" 
            Height="59" 
            Margin="513,280,0,0" 
            HorizontalAlignment="Left" 
            VerticalAlignment="Top" 
            Command="{Binding MyFirstCommand}" 
            CommandParameter="{Binding Text, 
                                       ElementName=myTextBox}" 
            Content="Execute Command" /> 


public class MyCommandsCollection 
{ 
    public MyCommand MyFirstCommand 
    { 
        get { return new MyCommand(); } 
    } 
} 

public class MyCommand : ICommand 
    { 
        public bool CanExecute(object parameter) 
        { 
            return true; 
        } 

        public event EventHandler CanExecuteChanged; 

        public async void Execute(object parameter) 
        { 
            MessageDialog message = new MessageDialog( 
                "The command is executing, the value of the TextBox is " + parameter as String); 
            await message.ShowAsync(); 
        } 
    }

I tried this out with x:Bind and it works nicely. All I need is to expose a property in my ViewModel that returns a new Instance of the "MyCommand" class and it's all good.

Since I'm setting the DataContext in my XAML, I didn't need to mess with any of the "MyCommandCollection" stuff. Yay compiled binding.

Trichloride answered 29/9, 2015 at 20:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.