takataka430’s blog

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

【Xamarin.Forms】CheckBoxをListView内で利用して複数選択する方法

少し前になりますが、Xamarin.Forms 4.1.0 Pre-Release でチェックボックスが使えるようになりましたね。

devblogs.microsoft.com

実は以前からListViewの要素を複数選択したかったので、これを見た瞬間に「これ使えばできるのでは!?」と思いやり方を調べてみました。iOSの編集モードのような機能を目指しています。それでは早速コードを見てみましょう。

環境

Visual Studio Community 2019 for Mac
Xamarin.Fomrs (4.1.0.496342 pre2)

コード

画面

<?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:CheckBox" 
             x:Class="CheckBox.MainPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="編集"
                     Clicked="Handle_Clicked"/>
    </ContentPage.ToolbarItems>
    <StackLayout>
        <ListView x:Name="list">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            
                            <!-- 2行1列のグリッドを作成 -->
                            <Grid.ColumnDefinitions>
                                
                                <!-- チェックボックスを表示する領域 -->
                                <ColumnDefinition Width="30"/>
                                
                                <ColumnDefinition Width="*"/>
                                
                            </Grid.ColumnDefinitions>
                            
                            <!-- Personクラスのプロパティにバインディング -->
                            <CheckBox IsChecked="{Binding IsChecked}"
                                      IsVisible="{Binding EditMode}"
                                      Grid.Column="0"/>
                            <Label Text="{Binding Name}"
                                   Grid.Column="1"
                                   VerticalOptions="Center"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

コードビハインド

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;

namespace CheckBox
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(true)]
    public partial class MainPage : ContentPage
    {
        //ListView表示用のコレクション
        private ObservableCollection<Person> person = new ObservableCollection<Person>
        {
            new Person{Name = "A"},
            new Person{Name = "B"},
            new Person{Name = "C"},
            new Person{Name = "D"},
            new Person{Name = "E"},
        };

        public MainPage()
        {
            InitializeComponent();

            //ListViewの要素を指定
            list.ItemsSource = person;
        }
        
        //チェックボックスの表示・非表示の切り替え
        void Handle_Clicked(object sender, EventArgs e)
        {
            foreach (var a in person)
            {
                if(a.EditMode == true)
                {
                    a.EditMode = false;
                    a.IsChecked = false;
                }
                else
                {
                    a.EditMode = true;
                }
            }
        }
    }

    //変更通知がいくようにしないとObservableCollectionの要素内のプロパティが変更されても画面に反映されない
    public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                if (name != value)
                {
                    this.name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }

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

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

コメントにも書いていますが、PersonクラスにINotifyPropertyChangedインターフェイスを継承させて変更通知が行くようにしないと、EditModeプロパティの値が変更されても画面に反映されません。

それでは画面の動きを見てましょう。

f:id:takataka430:20190629215441g:plain:w200

このコードでは表示・非表示の切り替えのみですが、例えばチェックした要素のみコレクションから削除する機能を実装すれば選択削除ができますね。
ぜひ試してみてください!
  
(2019/7/9 追記) 実装編も書きました↓ takataka430.hatenablog.com