0

I'm using WinUI MVVM (as an MVVM newbie)

Here is my button in XAML

<Button Grid.Row="0"  Content="Create New" Width="100" Margin="5"
        Command="{x:Bind ViewModel.CreateNewCommand }" 
        Visibility="{x:Bind ViewModel.IsCreateNewVisible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

In the constructor of the ViewModel I have this connection:

CreateNewCommand = new RelayCommand(Handle_CreateNewCommand, CanExecuteCreateNew);

and here is the CanExecute method:

public bool CanExecuteCreateNew()
{
    return IsCreateNewEnabled;
}

private bool _isCreateNewEnabled = false;
public bool IsCreateNewEnabled
{
    get => _isCreateNewEnabled;

    set
    {

        SetProperty(ref _isCreateNewEnabled, value);
    }
}

If I assign the IsCreateNewEnabled property in the VM constructor it renders correctly, enabled or disabled.

When I click the button it fires the handler method and before a single line of code in that method is executed, it fires the canExecute method with a value of true. In the handler method I set IsCreateNewEnabled = false but that has no effect on the button and doesn't fire the CanExecute method.

Any ideas?

Thanks

Carl

Andrew KeepCoding
  • 7,040
  • 2
  • 14
  • 21
CarlGanz
  • 189
  • 11
  • Why should setting IsCreateNewEnabled fire CanExecute of the CreateNewCommand ? how would you expect winui know that the member has any thing to do with the canexecute? Do you really think just because the canexecute happens to refer the member it somehow is magically connected? – Rand Random Oct 16 '22 at 13:16
  • 1
    In WPF you do this: https://stackoverflow.com/questions/1340302/wpf-how-to-force-a-command-to-re-evaluate-canexecute-via-its-commandbindings - maybe it is the same as in winui – Rand Random Oct 16 '22 at 13:18
  • 1
    `CanExecute` normally only evaluates once. If some condition changes, then you need to reevaluate. Depending on the type of command, you can call `RaiseCanExecuteChanged()` on the command – Julian Oct 16 '22 at 13:41
  • Even RaiseCanExecuteChanged() doesn;t see to do it. I'm firing this in the setter for public bool IsCreateNewEnabled CreateNewCommand.CanExecute(_isCreateNewEnabled) and the canExecute method fire but the button is still enabled – CarlGanz Oct 16 '22 at 13:54

1 Answers1

0

You can do it this way with the CommunityToolkit.Mvvm NuGet package.

ViewModel.cs

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

namespace Mvvm;

// This class needs to be "partial" for the CommunityToolkit.Mvvm.
public partial class YourViewModel : ObservableObject
{
    [RelayCommand(CanExecute = nameof(CanCreateNew))]
    // A "CreateNewCommand" command will be auto-generated.
    private void CreateNew()
    {
    }

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(CreateNewCommand))]
    // A "CanCreateNew" property that
    // notifies the "CreateNewCommand" to update its availability
    // will be auto-generated.
    private bool canCreateNew = false;
}

MainWindow.xaml.cs

using Microsoft.UI.Xaml;

namespace Mvvm;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    public YourViewModel ViewModel { get; } = new();
}

MainWindow.xaml

<Window
    x:Class="Mvvm.MainWindow"
    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"
    mc:Ignorable="d">

    <StackPanel>
        <Button
            Command="{x:Bind ViewModel.CreateNewCommand}"
            Content="Create New" />
        <ToggleButton
            Content="Can create new"
            IsChecked="{x:Bind ViewModel.CanCreateNew, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>

</Window>
Andrew KeepCoding
  • 7,040
  • 2
  • 14
  • 21
  • In MvvmLight the CanExecute got evaluated all the time, without the hazzle of wiring everything up like now. Just as an exampel: How would you bind CanExecute now to time? Is there still no option to make the RelayCommand work like it did before? I know this is due to Community Toolkit targeting multiple platforms but IMHO it's a PITA. – IngoB Apr 12 '23 at 15:44