Tag Archives: ICommand

MVVM Light CanExecute Command – Re-evaluate en-mass

MVVM Light CanExecute doesn’t work for commands

The following code in MVVM light does not work:

RelayCommand newCommand = new RelayCommand(onExecute, canExecute);

. . . 

canExecute = true;

. . .

canExecute = false;

That is, the bound command will not update. Even if the changed `canExecute` raises property changed.

Raise it manually

So, the way to fix this is as follows:

        public bool canExecute
        {
            get { return _canExecute; }
            set
            {
                _canExecute = value;
                RaisePropertyChanged();
                newCommand.RaiseCanExecuteChanged();
            }
        }

Which works fine. However, what if you have 10 commands, and they all have the same dependant property?

Real life

Here’s my method of working around this. Is it effectively a `RaiseAllPropertyChanged()` for commands. Start with a class level list of commands:

        // Store a local list of all registered commands to inform of updates
        private List<RelayCommand> _registeredCommands;

Now create a function that allows us to iterate this and call RaiseCanExecuteChanged to all of them:

        private void ReevaluateCommands()
        {
            foreach (var eachCommand in _registeredCommands)
            {
                eachCommand.RaiseCanExecuteChanged();
            }

        }

Finally, we can simply call this when the dependant property changes:

        public bool canExecute
        {
            get { return _canExecute; }
            set
            {
                _canExecute = value;
                RaisePropertyChanged();
                ReevaluateCommands();
            }
        }

Magic.

Disclaimer

I kind of stole the idea for this from here. I’m not selling this as a massively scalable, all singing, all dancing solution. It just works for my particular scenario, which is here:

TFS Utilities

MVVM Cross Basics – Navigating Using Commands

I’m quite new to MVVM Cross. I thought I’d start another series of posts on my progress (I haven’t forgotten about the others). Especially where I haven’t found as much documentation as I’d like. My latest project is a game written using the MVVM Cross framework; it’s not a shoot-em-up or an action game, but it will be a game. When it’s finished, I’ll post a link if I get it in any of the stores.

Quick Tips

So far, the best place to go if you’re new to MVVM Cross is Stuart Lodges videos:

https://www.youtube.com/watch?v=_DHDMNB_IeY

Stuart is also a regular of Stack Overflow.

Navigation

The way that MVVM Cross works is slightly different to what I would have expected, in that the ViewModel is the key to the navigation. The view is then determined using a naming convention. In this example, I’m starting the application in a ViewModel called Home, and navigating to Main. Home will display the “New Game / Continue Game” dialog, and Main will be the main game screen.

This blog post is not intended to show how to set-up a new MVVM Cross project; however, essentially my game architecture is as follows:

Game Solution
– Game.PCL
– Game.Windows
– Game.WindowsPhone (currently disabled as this doesn’t work)
– Game.Shared

I have no idea whether this will work, but I think it should. If it doesn’t then I’m sure there’ll be some useful lessons on the way.

MvxCommand – the ViewModel

There is a in-built command type called MvxCommand, and that is what I’m going to use. Here’s how I set-up my VM:

    public class HomeViewModel : BaseViewModel
    {
        private MvxCommand _startNewGameCommand;
        private MvxCommand _continueExistingGameCommand;

        public IMvxCommand StartNewGameCommand
        {
            get
            {
                return _startNewGameCommand;
            }
        }

        public IMvxCommand ContinueExistingGameCommand
        {
            get
            {
                return _continueExistingGameCommand;
            }
        }

        public override void Start()
        {
            _startNewGameCommand = new MvxCommand(() => StartNewGame());
            _continueExistingGameCommand = new MvxCommand(() => ContinueExistingGame());

            base.Start();
        }

        private void ContinueExistingGame()
        {
            throw new NotImplementedException();
        }

        private void StartNewGame()
        {
            ShowViewModel<MainViewModel>();
        }
    }

ShowViewModel is the key here. It navigates to the MainViewModel. MVVMCross uses a convention whereby the view that is shown is based on the VM name; so the view here must be called MainView.

The View

The source view (In this case HomeView) looks like this:

<views:MvxStorePage
    x:Class="MyGame.Views.HomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="using:Cirrious.MvvmCross.WindowsStore.Views"
    mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Command="{Binding StartNewGameCommand}" HorizontalAlignment="Center">Start New Game</Button>
            <Button Command="{Binding ContinueExistingGameCommand}" HorizontalAlignment="Center">Continue Existing Game</Button>
        </StackPanel>
    </Grid>
</views:MvxStorePage>

Pretty simple command binding. Now, providing that the destination View and ViewModel exist, and inherit from MvxStorePage, your navigation should now work.

Conclusion

Just the rest of the game to write now…

Windows Tile Updater (Part 7 – Multibinding command parameters)

We left the last post where the Tile Updater could update text, or images, but we basically had to choose which at design time. In this post, I’m going to pass through the image and text, and have the command work out which to update.

Note: you can have both image and text in live tiles. Look out for that in a future post.

Multibinding

The first thing to know about multibinding for WinRT is that it doesn’t exist. However, to get around this, we can simply take the same approach that we do with a function – a function can only return one value, but that value can be a class; so we’ll bind to the VM (one of the advantages of exposing a static singleton instance of the VM):

<Button Grid.Row="2" Command="{Binding UpdateCommand}" CommandParameter="{Binding MVM}">Update</Button>        

The command itself needs to look something like this for now:

        public bool CanExecute(object parameter)
        {
            MainViewModel mvmInst = (MainViewModel)parameter;
            if (mvmInst == null) return false;

            if (string.IsNullOrWhiteSpace(mvmInst.ImagePath) &amp;&amp; string.IsNullOrWhiteSpace(mvmInst.DisplayText))
                return false;
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            MainViewModel mvmInst = (MainViewModel)parameter;

            if (string.IsNullOrWhiteSpace(mvmInst.ImagePath))
                TileUpdater.Model.UpdateTile.UpdateTileText(mvmInst.DisplayText);
            else
                TileUpdater.Model.UpdateTile.UpdateTileImage(mvmInst.ImagePath);
        }

There’s a couple of points here:
1. The CanExecute will not prevent the command from firing where neither parameter has a value.
2. It doesn’t disable the button when this occurs.

And that’s it – we now have a command that can accept multiple parameters and update either image or text depending on what is displayed.

Conclusion

Okay, strictly speaking, this is not multi-binding. It does however, solve the problem. I suppose the design question would be: does it introduce a tighter coupling than multi-binding?

It definitely does; however, with a bit of manipulation, you could introduce a mini-VM that just had the parameters that you need. However, for most cases, I would think that it was fine to just pass the VM to the command. We’ll see if this comes back to bite me when we start putting some unit tests in place.