takataka430’s blog

Xamarin.Formsを中心に勉強したことのまとめを書きます

【Xamarin.Forms】ToolbarItemを有効化・無効化する方法

以前Xamarin.Formsで画面の操作をロックする方法(ナビゲーションバー含む)という記事を書きました。その記事では画面全体をContentPageで覆ってもナビゲーションバーが隠れないのでナビゲーションバーを含めた画面全体を覆う方法を考えました。しかし、よく考えたらナビゲーションバーのボタン、つまりToolbarItemを無効化する方法もあるのでは?と思い、その方法を調べました。

結論から言いますと、ToolbarItemのCommandプロパティをバインドすることで実現することができました。コマンドを実行できる場合はボタンが有効、実行できない場合はボタンが無効になるようです。
(ちなみに、ToolbarItemはIsEnableプロパティも持っているようなので最初はこちらを使おうと思いましたが、うまくいきませんでした。)

環境

Visual Studio Community 2017 for Mac
Xamarin.Forms (3.6.0.220655)

コード

画面は次の通りです。コードビハインドはInitializeComponent()のみの記載です。ToolbarItemのCommandプロパティをバインドします。

MainPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:local="clr-namespace:XF_Overlay" 
             x:Class="XF_Overlay.MainPage">
    <ContentPage.BindingContext>
        <local:MainPageViewModel/>
    </ContentPage.BindingContext>
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Test"
                     Command="{Binding TBCommand}"/>  <!-- ここでバインド -->
    </ContentPage.ToolbarItems>
    <AbsoluteLayout>
        <StackLayout AbsoluteLayout.LayoutFlags="All"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     VerticalOptions="Center">
            <Button Command="{Binding OverlayClicked}"
                    Text="OverlayVer2"/>
        </StackLayout>
        <ContentView x:Name="bglayer"
                     BackgroundColor="Black"
                     Opacity="0.4"
                     IsVisible="{Binding IsBusy}"
                     AbsoluteLayout.LayoutFlags="All"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"/>
            <Frame  x:Name="frame"
                    IsVisible="{Binding IsBusy}"
                    AbsoluteLayout.LayoutFlags="PositionProportional"
                    AbsoluteLayout.LayoutBounds="0.5,0.5,AutoSize,AutoSize">
                <StackLayout>
                    <ActivityIndicator  Color="Black"
                                        IsRunning="true"/>
                    <Label Text="処理中です" />
                </StackLayout>
            </Frame>
    </AbsoluteLayout>
</ContentPage>

  
ビューモデルは次のようになります。有効・無効の値を入れるためにIsEnableプロパティを作成します。Commandの第2引数であるChangeCanExecuteにIsEnableプロパティを指定し、このプロパティの値を変更するたびにコマンドの実行可否を再評価します。前述の通りコマンドが実行可能な場合はボタンが有効に、実行不可能な場合はボタンが無効になるようなので、それを利用しています。

MainPageViewModel.cs

using System.ComponentModel;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XF_Overlay
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            IsEnable = true;
            IsBusy = false;

            OverlayClicked = new Command(async() =>
            {
                IsEnable = false;
                IsBusy = true;
                TBCommand.ChangeCanExecute();  //コマンドの実行可否を再評価
                await Task.Delay(2000);
                IsEnable = true;
                IsBusy = false;
                TBCommand.ChangeCanExecute();  //コマンドの実行可否を再評価
            });

            //コマンドの実行可否をIsEnableプロパティによって決定
            TBCommand = new Command( () =>
            {

            }, ()=> IsEnable);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public Command OverlayClicked { get; }
        public Command TBCommand { get; set; }

        public bool IsEnable { get; set; }

        private bool isBusy;
        public bool IsBusy
        {
            get { return isBusy; }
            set
            {
                if(isBusy != value)
                {
                    isBusy = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBusy)));
                }
            }
        }
    }
}

動きは下のような感じです。

f:id:takataka430:20190307214501g:plain:w200

処理中は右上のTestボタンが押せなくなっていますね!

参考にしたサイト

ToolbarItem を Disable 状態にする方法 | Xamarin.Forms - ITブログ時々なんでもブログ

Xamarin.Forms の Command でも CanExecute でボタンを制御 - Xamarin 日本語情報