読者です 読者をやめる 読者になる 読者になる

Xamarin 日本語情報

Xamarin(ザマリン) の代理店だったエクセルソフト田淵のブログです。主に Xamarin に関するエントリーをアップしていきます。(なるべく正しい有益な情報を掲載していきたいと考えていますが、このブログのエントリーは所属組織の公式見解ではありませんのでご注意ください)

Xamarin.Forms で複数の Switch を動かす Switch を作るには

Xamarin Xamarin.Forms

こんにちは。エクセルソフトの田淵です。

まぁあれです。IT勉強会検索アプリを作成してまして。関東 Switch をトグルすると 東京、神奈川〜 みたいに関東全件をトグルする。とかそういうことがしたかったわけです。

呟いたところ、有識者の皆さんが寄ってたかって色々考えて教えてくださいまして。本当にありがたいです涙 @yakumomo さんは Qiita エントリー まで書いてくださいました。ありがとうございます!

色々なやり方がありますが、各 Switch の値は ViewModel に保存しておきたいので、プロパティのところでイジるのが良いのではというところに落ち着きました。

画面写真

f:id:ytabuchi:20150711112530p:plain:w150 f:id:ytabuchi:20150711112532p:plain:w150

View

Xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:vm="clr-namespace:XF_ManySwitches;assembly=XF_ManySwitches" 
             x:Class="XF_ManySwitches.SwitchPageXaml"
             Title="SwitchPage Xaml">
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness" 
      iOS="0,20,0,0" 
      Android="0" 
      WinPhone="0" />
  </ContentPage.Padding>
  <ContentPage.BindingContext>
    <vm:SwitchPageViewModel />
  </ContentPage.BindingContext>
  <ContentPage.Content>
    <TableView Intent="Menu">
      <TableRoot>
        <TableSection Title="Toggle all">
          <SwitchCell Text="Toggle sw1 &amp; sw2" 
                      On="{Binding SwAllValue, Mode=OneWayToSource}" />
        </TableSection>
        <TableSection Title="Toggle each">
          <SwitchCell Text="Toggle sw1" 
                      On="{Binding Sw1Value, Mode=TwoWay}" />
          <SwitchCell Text="Toggle sw2" 
                      On="{Binding Sw2Value, Mode=TwoWay}" />
        </TableSection>
        <TableSection Title="Values of ViewModel">
          <TextCell Text="sw1 value" 
                    Detail="{Binding Sw1Value}" />
          <TextCell Text="sw2 value" 
                    Detail="{Binding Sw2Value}" />
        </TableSection>
      </TableRoot>
    </TableView>
  </ContentPage.Content>
</ContentPage>

C#

SwitchPageViewModel vm = new SwitchPageViewModel();
BindingContext = vm;

var sw0 = new SwitchCell { Text = "Toggle sw1 & sw2" };
sw0.SetBinding(SwitchCell.OnProperty, "SwAllValue", BindingMode.OneWayToSource);
var sw1 = new SwitchCell { Text = "Toggle sw1" };
sw1.SetBinding(SwitchCell.OnProperty, "Sw1Value", BindingMode.TwoWay);
var sw2 = new SwitchCell { Text = "Toggle sw2" };
sw2.SetBinding(SwitchCell.OnProperty, "Sw2Value", BindingMode.TwoWay);
var tc1 = new TextCell { Text = "sw1 value" };
tc1.SetBinding(TextCell.DetailProperty, "Sw1Value");
var tc2 = new TextCell { Text = "sw2 value" };
tc2.SetBinding(TextCell.DetailProperty, "Sw2Value");

var tv = new TableView
{
    Intent = TableIntent.Menu,
    Root = new TableRoot
    {
        new TableSection("Toggle all")
        {
            sw0,
        },

        new TableSection("Toggle each")
        {
            sw1,
            sw2,
        },
        new TableSection("Values of ViewModel")
        {
            tc1,
            tc2,
        }
    }
};

Content = new StackLayout
{ 
    Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
    Children =
    {
        tv,
    }
};

ViewModel

bool _sw1Value;

public bool Sw1Value
{
    get { return _sw1Value; }
    set
    {
        if (_sw1Value != value)
        {
            _sw1Value = value;
            OnPropertyChanged("Sw1Value");
        }
    }
}

bool _sw2Value;

public bool Sw2Value
{
    get { return _sw2Value; }
    set
    {
        if (_sw2Value != value)
        {
            _sw2Value = value;
            OnPropertyChanged("Sw2Value");
        }
    }
}

bool _swAllValue;

public bool SwAllValue
{
    get { return _swAllValue; }
    set
    {
        if (_swAllValue != value)
        {
            _swAllValue = value;
            OnPropertyChanged("SwAllValue");
        }
        if (_sw1Value != value)
        {
            _sw1Value = value;
            OnPropertyChanged("Sw1Value");
        }
        if (_sw2Value != value)
        {
            _sw2Value = value;
            OnPropertyChanged("Sw2Value");
        }
    }
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this,
            new PropertyChangedEventArgs(propertyName));
    }
}

ポイント

  • ViewModel の一括で変更する「変更元 Switch」側で変更したい Switch の value を一緒にチェックして変更するようにします。
  • 変更元 Switch では BindingMode を OneWayToSource として ViewModel に伝えるだけにします。

これで「変更先 Switch」を自由に変更しつつ、変更元 Switch をトグルした時だけ一括で変更できます。

今回は Switch ですが、何かのヒントになれば嬉しいです。

なお、Xamarin.Forms の Xaml ですが、{Binding の後のプロパティに IntelliSense が効かず、何を Binding すれば良いかイマイチ分かりません。コードは凄い冗長になってしまいますが、C# で書くと IntelliSense で何を Binding するのか分かるので、先に C# で書いてみるのが良いかもしれません。

Xamarin 気になった方は

Mvvm の勉強にも最適な Xamarin.Forms、イイですね!

是非 ダウンロード(直接) / ダウンロード(弊社経由) して触ってみてください。 学習用リソースJXUG リンクページ に参考資料を纏めてますので併せてどうぞ。

Xamarin の情報が欲しい方はこのブログも購読いただいたりすると嬉しいです。

以上です。