Search code examples
wpfmvvmviewmodeltoolkit

RelayCommand (MVVM Toolkit) Simple Demo explaination


Hi stackoverflow community, I'm new to the MVVM topic but was able to get some of the basics down. I worked on a few tutorials and implemented my own RealyCommand and a ViewModelBase.

I got my Buttons working with Command Binding and Enable/Disable with CanExecute was working as well.

MVVM Toolkit: After implementing MVVM Toolkit for messaging, I have looked into more examples on MS page and saw that the toolkit provides RelayCommand and a lot more features with way less code, so I wanted to replace my own MVVM code with code for MVVM Toolkit.

For the life of it, I can't figure out why the canExecute doesn't work, It updates the bool variables from true to false and vice versa but the button does not go enabled/disabled. What am I missing?

TestViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;


namespace WorkOrderApplication.ViewModels
{
    public partial class TestViewModel : ObservableObject
    {
        public TestViewModel()
        {
            Testbutton1 = true;
            Testbutton2 = true;
        }


        [ObservableProperty]
        private bool _testbutton1;

        [ObservableProperty]
        private bool _testbutton2;


        [RelayCommand(CanExecute = nameof(CanExecuteButton1))]
        private void ClickButton1()
        {
            Testbutton1 = false;
            Testbutton2 = true;
        }

        private bool CanExecuteButton1()
        {
            return Testbutton1;
        }

        [RelayCommand(CanExecute = nameof(CanExecuteButton2))]
        public void ClickButton2()
        {
            Testbutton1 = true;
            Testbutton2 = false;
        }

        private bool CanExecuteButton2()
        {
            return Testbutton2;
        }
    }
}

TestView:

<UserControl x:Class="WorkOrderApplication.Views.TestView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         
         xmlns:designer="clr-namespace:WorkOrderApplication.ViewModels.Designer" 
         xmlns:customcontrol="clr-namespace:WorkOrderApplication.Views.Controls"
         xmlns:viewmodels="clr-namespace:WorkOrderApplication.ViewModels"
         mc:Ignorable="d"
         d:DesignWidth="1920"
         d:DesignHeight="1080">

<UserControl.Resources>
    <Style TargetType="Button" x:Key="RoundButton">
        <Style.Resources>
            <Style TargetType="Border">
                <Setter Property="CornerRadius" Value="10" />
            </Style>
        </Style.Resources>
        <Setter Property="FontSize" Value="30"/>
        <Setter Property="Foreground" Value="white"/>
        <Setter Property="Background" Value="green"/>
        <Setter Property="Width" Value="130"/>
        <Setter Property="Height" Value="50"/>
        <Setter Property="BorderThickness" Value="0"/>
    </Style>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</UserControl.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="140"/>
        <RowDefinition Height="940"/>
    </Grid.RowDefinitions>

    <Grid Grid.Row="0" Margin="0,0,0,0" Background="White">
        <DockPanel Margin="0,0,0,0">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="135"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="166"/>
                    <ColumnDefinition Width="166"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <Button Content="Button 1" Grid.Column="0" 
                        Style="{DynamicResource RoundButton}"
                        Command="{Binding ClickButton1Command}">
                </Button>

                <Button Content="Button 2" Grid.Column="1"  
                        Style="{DynamicResource RoundButton}"
                        Command="{Binding ClickButton2Command}">
                </Button>
            </Grid>
        </DockPanel>
    </Grid>

    <Grid Grid.Row="1" Margin="0,0,0,0" Background="White">
        <Label Content="Content:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontSize="60" Height="100" Width="300"/>
    </Grid>

</Grid>

Solution

  • According to the docs you have to set the NotifyCanExecuteChangedFor attribute

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    
    
    namespace WorkOrderApplication.ViewModels
    {
        public partial class TestViewModel : ObservableObject
        {
            public TestViewModel()
            {
                Testbutton1 = true;
                Testbutton2 = true;
            }
    
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(ClickButton1Command))]
            private bool _testbutton1;
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(ClickButton2Command))]
            private bool _testbutton2;
    
    
            [RelayCommand(CanExecute = nameof(CanExecuteButton1))]
            private void ClickButton1()
            {
                Testbutton1 = false;
                Testbutton2 = true;
            }
    
            private bool CanExecuteButton1()
            {
                return Testbutton1;
            }
    
            [RelayCommand(CanExecute = nameof(CanExecuteButton2))]
            public void ClickButton2()
            {
                Testbutton1 = true;
                Testbutton2 = false;
            }
    
            private bool CanExecuteButton2()
            {
                return Testbutton2;
            }
        }
    }