9

I'm facing a problem with ToolbarItem and IsEnabled property when trying to turn it on/off from XAML using triggers. ToolbarItem doesn't support triggers, so what I do is to create a Button (a hidden one) which supports triggers and then bind Button.IsEnabled to ToolbarItem.IsEnabled; here is the sample code:

    <ContentPage.ToolbarItems>
        <ToolbarItem x:Name="tlbSave" Text="Save" Clicked="Handle_Clicked">
            <ToolbarItem.IsEnabled>
                <Binding Source="{x:Reference btnTest}" Path="IsEnabled" />
            </ToolbarItem.IsEnabled>
        </ToolbarItem>
    </ContentPage.ToolbarItems>

    <ContentPage.Content>

        <StackLayout Padding="10" VerticalOptions="CenterAndExpand">

            <Entry x:Name="txtTest" HorizontalOptions="FillAndExpand" />

            <Button x:Name="btnTest" Text="HIDDEN" IsEnabled="false" HorizontalOptions="FillAndExpand">
                <Button.Triggers>
                    <MultiTrigger TargetType="Button">
                        <MultiTrigger.Conditions>
                            <BindingCondition Binding="{Binding Source={x:Reference txtTest}, Path=Text.Length,
                                                           Converter={convert:IsPositiveIntegerConverter}}" Value="true" />
                        </MultiTrigger.Conditions>

                        <Setter Property="IsEnabled" Value="True" />
                    </MultiTrigger>
                </Button.Triggers>
            </Button>

        </StackLayout>

    </ContentPage.Content>

If you try this piece of code you will see how btnTest gets enable/disable when txtTest.Text has some value. But it isn't affecting tlbSave.IsEnabled property.

However, this work perfect in code behind when I set tlbSave.IsEnabled into btnText.PropertyChanged EventHandler

btnTest.IsVisible is false, I'm just showing it up for testing purposes.

Any idea about how to deal with this?

Saimel Saez
  • 319
  • 4
  • 8

2 Answers2

8

This is because of the IsEnabled property of ToolbarItem is read-only.

If you just set IsEnabled property of a toolbar item in your XAML to false or true, you will get the following exception at runtime.

System.InvalidOperationException: The BindableProperty "IsEnabled" is readonly.

And if you take a look at Microsoft's documentation, you will notice that you cannot directly set IsEnabled property of a toolbar item.

For disabling a toolbar item, the suggested way is to use a command and it's CanExecute.

Armin Rasoulian
  • 271
  • 1
  • 9
  • 2
    In XAML we can't assign a boolean value to `IsEnabled` because it's a bindable property. However in code behind I can change its value. – Saimel Saez Mar 15 '19 at 15:04
  • "For disabling a toolbar item," does that work for you? I've seen bug reports from 2015 saying it doesn't disable based on CanExecute and still executes. I am on XF 4.4 and the CanExecute does not seem to be be respected even now – Pat Long - Munkii Yebee May 06 '20 at 14:49
  • From where do you see it's read only? There is a getter and a setter. The only notice I can see is *For internal use by the Xamarin.Forms platform.* – testing Apr 09 '21 at 13:22
2

I found out a way to solve this problem, at least a way better than implementing OnPropertyChange for btnTest

    <ContentPage.ToolbarItems>
        <ToolbarItem x:Name="tlbSave" Text="Save" Clicked="Handle_Clicked" />
    </ContentPage.ToolbarItems>

    <ContentPage.Content>

        <StackLayout Padding="10" VerticalOptions="CenterAndExpand">

            <Entry x:Name="txtTest" HorizontalOptions="FillAndExpand" />

            <Button x:Name="btnTest" Text="HIDDEN">
                <Button.Triggers>
                    <MultiTrigger TargetType="Button">
                        <MultiTrigger.Conditions>
                            <BindingCondition Binding="{Binding Source={x:Reference txtTest}, Path=Text.Length,
                                                           Converter={convert:IsPositiveIntegerConverter}}" Value="true" />
                        </MultiTrigger.Conditions>

                        <Setter Property="IsEnabled" Value="True" />
                    </MultiTrigger>
                </Button.Triggers>

                <Button.IsEnabled>
                    <Binding Source="{x:Reference tlbSave}" Path="IsEnabled" Mode="OneWayToSource" />
                </Button.IsEnabled>
            </Button>

        </StackLayout>

    </ContentPage.Content>

Then set btnTest.IsEnabled = false; inside constructor and everything will go as smooth as I want.

Saimel Saez
  • 319
  • 4
  • 8