Frank Mehlhop
Frank Mehlhop

Reputation: 2222

Maui How to disable a button when using Command-binding

I am using a command binding for a button in Maui. The button's IsEnabled property does not work because of the command binding. Even if IsEnable is set to true, the command is not fired. How can I disable the button in the ViewModel class at the constructor in new Command(..) so that the command does not fire and the button looks disabled? (Like toggling from one to the other button.)

On learn.microsoft.. I read:

Warning

Do not use the IsEnabled property of Button if you're using the command interface.

XAML:

<ScrollView Style="{StaticResource mainScrollView}">
    <VerticalStackLayout>

        <HorizontalStackLayout>
            <Button Text="Month" 
                    Command="{Binding SetMonatCommand}"
                    Style="{StaticResource buttonCalendar}"
                    IsEnabled="{Binding IsListActive}"/> <!-- IsEnabled IS NOT WORKING -->
            <Button Text="List" 
                    Command="{Binding SetListeCommand}"
                    Style="{StaticResource buttonCalendar}"
                    IsEnabled="{Binding IsMonthActive}"/> <!-- IsEnabled IS NOT WORKING -->
        </HorizontalStackLayout> ...

ViewModel:

public partial class CalendarPageViewModel : ObservableObject, INotifyPropertyChanged
{
private readonly CalendarService _calendarService;

[ObservableProperty]
private bool _isMonthActive;

[ObservableProperty]
private bool _IsListActive;

public ICommand SetMonthCommand { get; set; }

public ICommand SetListCommand { get; set; }

public CalendarPageViewModel(CalendarService calendarService)
{
    _calendarService = calendarService;

    SetMonthCommand = new Command(() =>
    {
        IsMonthActive = true;
        IsListActive = !IsMonthActive;
    }); // is not called when using IsEnabled at the XAML

    SetListCommand = new Command(() =>
    {
        IsListActive = true;
        IsMonthActive = !IsListActive;
    }); // is not called when using IsEnabled at the XAML
} ....

Upvotes: 1

Views: 5215

Answers (3)

Kramer
Kramer

Reputation: 431

You should use the CanExecute() method, so that the button will be set to IsEnabled=false based on the boolean property in your ViewModel. This way you only need one boolean whether the month or list is shown, also do not forget to call NotifyCanExecuteChanged() on your command, so that it re-evaluates the CanExecute() method. You can also use the handy RelayCommand attribute from the CommunityToolkit.Mvvm nuget package.

        [ObservableProperty]
        private bool _IsListActive = true;

        [RelayCommand(CanExecute = nameof(CanSetMonth))]
        private void SetMonth()
        {
            IsListActive = false;
            SetMonthCommand.NotifyCanExecuteChanged();
            SetListCommand.NotifyCanExecuteChanged();
        }

        private bool CanSetMonth()
        {
            return IsListActive;
        }

        [RelayCommand(CanExecute = nameof(CanSetList))]
        private void SetList()
        {
            IsListActive = true;
            SetMonthCommand.NotifyCanExecuteChanged();
            SetListCommand.NotifyCanExecuteChanged();
        }

        private bool CanSetList()
        {
            return !IsListActive;
        }

To make the button look disabled, you could use the VisualStateManager, which should be already in styles.xaml when you create a new MAUI project.

    <Style TargetType="Button">
        <Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource White}}" />
        <Setter Property="VisualStateManager.VisualStateGroups">
            <VisualStateGroupList>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal" />
                    <VisualState x:Name="Disabled">
                        <VisualState.Setters>
                            <Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Gray950}, Dark={StaticResource Gray200}}" />
                            <Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray600}}" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateGroupList>
        </Setter>
    </Style>

The xaml code:

        <Button Text="Set Month" Command="{Binding SetMonthCommand}" />
        <Button Text="Set List" Command="{Binding SetListCommand}" />

Upvotes: 4

Liyun Zhang - MSFT
Liyun Zhang - MSFT

Reputation: 14244

First of all, when you declared the variable such as private bool _isMonthActive without setting it value. It will used the bool's default value(false). It mean the button will be disabled as first and the command can't be executed.

In addition, I have create a new project to test your code and found that the command will not execute even though I set the isMonthActive and _IsListActive as true. So I used the RelayCommand instead of the ICommand. Such as:

 public partial class CalendarPageViewModel : ObservableObject
    {
       

        [ObservableProperty]
        private bool _isMonthActive ;

        [ObservableProperty]
        private bool _IsListActive ;


        public CalendarPageViewModel(CalendarService calendarService)
        {
             IsMonthActive = true;
             IsListActive = true;
        }
        [RelayCommand]
        public void Test1()
        {
            IsMonthActive = false;
            IsListActive = !IsMonthActive;
        }
        [RelayCommand]
        public void Test2()
        {
            IsListActive = false;
            IsMonthActive = !IsListActive;
        }
       
    }

And use it in the xaml:

 <Button Text="Month"
                    Command="{Binding Test1Command}"    
                    IsEnabled="{Binding IsListActive}"/>
 
        <Button Text="List"
                    Command="{Binding Test2Command}"
                    IsEnabled="{Binding IsMonthActive}"/>
        </Button>

The command will execute. Note: the button's command is disabled when the button's IsEnabled property is false. So if you want to excute the command, you need to set the button's IsEnabled property as true.

Upvotes: 0

Himanshu Dwivedi
Himanshu Dwivedi

Reputation: 8174

If a button has the Command attribute, it’s IsEnabled attribute is disregarded, and the button remains enabled. However, if you bind the Command attribute, then the state of the IsEnabled attribute depends on the CanExecute state of your Command. Rather than binding IsEnabled directly, it's better to include the necessary logic in the CanExecute state of your command.

public ICommand SetMonthCommand { get; set; }

public CalendarPageViewModel(CalendarService calendarService)
{
    SetMonthCommand = new Command(ExecuteSetMonthCommand, CanExecuteSetMonthCommand);
}

private void ExecuteSetMonthCommand()
{
    IsMonthActive = true;
    IsListActive = !IsMonthActive;
}

private bool CanExecuteSetMonthCommand()
{
    return IsMonthActive;
}

Upvotes: 0

Related Questions