【Xamarin.Forms】コンテキストメニューでListViewから行を削除する
はじめに
Xamarin.FormsのListViewで行のコンテキストメニューからその行を削除します。
コードビハインドは書かず、MVVMで実現します。
最初に言い訳です。
この記事を書いてみて、Xamarin.Fromsの基礎がわかったいないことを改めて自覚。。。
https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/app-fundamentals/
曖昧な表現がありますので、予めご了承ください。
したいこと(できたこと)
環境
Visual Studio Community 2019 for Mac
Xamarin.Forms 4.2.0
Prism.Unity.Forms 7.2.0(オプション)
ソース
GitHubにソースを上げています。
https://github.com/ats-y/TryXamarinListViewContextMenu
以下、上記ソースを抜粋して説明します。
説明
ViewとViewModelにわけて説明します。
View
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="TryContextMenu.MainPage"
x:Name="MainPageContentPage">
<StackLayout>
<!-- 社員一覧 -->
<ListView x:Name="EmployeeListView"
ItemsSource="{Binding EmployeeList}"
HasUnevenRows="True">
<!-- 社員行 -->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- コンテキストメニューの定義-->
<ViewCell.ContextActions>
<!--
削除コンテキストメニュー
Command属性:タップするとMainPageContentPageのDeleteCommandを呼び出す。
CommandParameter属性:Command属性で指定したコマンドに渡すデータを指定。-->
<MenuItem Text="削除"
IsDestructive="True"
Command="{Binding Source={x:Reference MainPageContentPage}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding .}" />
</ViewCell.ContextActions>
<!-- レイアウト定義 -->
<StackLayout Padding="10,100,0,100"
BackgroundColor="{Binding BackColor}"
HorizontalOptions="FillAndExpand"
Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="名前:" />
<Label Text="{Binding FullName}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Viewのポイント
コードビハインド(MainPage.xaml.cs)
今回やりたいことを実現するにあたって、コードビハインドには特に何も書いていません。
ルートContentPageの名前付け
ルートのContentPage要素には「MainPageContentPage」という名前をつけています。
<ContentPage (略)
x:Name="MainPageContentPage">
削除コンテキストの定義
MenuItem要素で削除コンテキストメニューを定義します。
<!--
削除コンテキストメニュー
Command属性:タップするとMainPageContentPageのDeleteCommandを呼び出す。
CommandParameter属性:Command属性で指定したコマンドに渡すデータを指定。-->
<MenuItem Text="削除"
IsDestructive="True"
Command="{Binding Source={x:Reference MainPageContentPage}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding .}" />
Command属性、CommandParameter属性でコンテキストメニューをタップした時のコマンドとコマンドに渡すパラメータを定義しています。
Command属性で指定した値によって、
「MainPageContentPageに紐づいているViewModelのDeleteCommandを呼び出してね」
と定義しています。
「MainPageContentPage」はルートのContentPage要素につけた名前です。
CommandParameter属性はCommand属性で指定したコマンドを呼び出すときに渡す値を定義します。
{Binding .}
とすることでタップした行データ、つまりListView要素のItemSource属性に紐づいているListのタップした行の要素が渡されました。
ViewModel
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using TryContextMenu.Models;
using Xamarin.Forms;
namespace TryContextMenu.ViewModels
{
public class MainPageViewModel : ViewModelBase
{
/// <summary>
/// 社員リスト
/// </summary>
private ObservableCollection<Employee> _employeeList;
/// <summary>
/// 社員リストプロパティ
/// </summary>
public ObservableCollection<Employee> EmployeeList
{
get { return _employeeList; }
set { SetProperty(ref _employeeList, value); }
}
/// <summary>
/// コンストラクタ
/// </summary>
public MainPageViewModel()
{
// 社員リストを生成する。
_employeeList = new ObservableCollection<Employee>
{
new Employee { FullName = "社員 太郎" },
new Employee { FullName = "社員 二郎" },
new Employee { FullName = "社員 三郎" },
new Employee { FullName = "社員 四郎" },
new Employee { FullName = "社員 五郎" },
};
}
/// <summary>
/// 社員リストから引数で指定した社員を削除する。
/// </summary>
public ICommand DeleteCommand =>
new Command<Employee>((arg) =>
{
Debug.WriteLine("MainPage.DeleteCommand()");
EmployeeList.Remove(arg);
});
}
}
ViewModelのポイント
社員リストおよびプロパティ
/// <summary>
/// 社員リスト
/// </summary>
private ObservableCollection<Employee> _employeeList;
/// <summary>
/// 社員リストプロパティ
/// </summary>
public ObservableCollection<Employee> EmployeeList
{
get { return _employeeList; }
set { SetProperty(ref _employeeList, value); }
}
EmployeeListプロパティは社員リストです。
MainPageViewModelクラスに対するView「MainPage.xaml」のListViewのItemSource属性で指定したバインディングItemsSource="{Binding EmployeeList}"
と同じ名前にすることで、社員ListViewのリストデータとMainPageViewModel.EmployeeListが紐づきます。
これにより、MainPageViewModel.EmployeeListに入れたデータがListViewに表示されます。
今回はMainPageViewクラスのコンストラクタでEmployeeListプロパティに社員リストに社員を追加していて、実行すると追加した社員がListViewに表示されます。
/// <summary>
/// コンストラクタ
/// </summary>
public MainPageViewModel()
{
// 社員リストを生成する。
_employeeList = new ObservableCollection<Employee>
{
new Employee { FullName = "社員 太郎" },
new Employee { FullName = "社員 二郎" },
new Employee { FullName = "社員 三郎" },
new Employee { FullName = "社員 四郎" },
new Employee { FullName = "社員 五郎" },
};
}
また、ObservableCollection<Employee>型にすることで、社員リストプロパティの内容が変わるとViewに反映されるようになります。
DeleteCommandコマンド
/// <summary>
/// 社員リストから引数で指定した社員を削除する。
/// </summary>
public ICommand DeleteCommand =>
new Command<Employee>((arg) =>
{
Debug.WriteLine("MainPage.DeleteCommand()");
EmployeeList.Remove(arg);
});
削除コンテキストのMenuItem要素のCommand属性で指定したPathと同じ名前でICommand型で定義します。そして、CommandParameter属性で渡すことにした型を型引数にしています。
引数argには、削除コンテキストをタップした行のEmployeeオブジェクトが渡されます。
EmployeeList.Remove(arg);
で社員リストプロパティから、argで渡されたEmployeeオブジェクトを削除します。
社員リストはObservableCollection<>型なので、これで社員ListViewから当該社員行が削除されます。
Author And Source
この問題について(【Xamarin.Forms】コンテキストメニューでListViewから行を削除する), 我々は、より多くの情報をここで見つけました https://qiita.com/ats-y/items/5799575b4531e9274315著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .