Xamarin.Formsにクロスプラットフォームアプリケーションを開発しています。
ページの1つでは、アイテムの同じリストを持つ3つのピッカーのセットを表示する必要があります。アイデアは、ピッカーの1つでアイテムを選択すると、他の2つのアイテムソースから削除されます。
これを行うには、次のコードを作成しました:
Webサービスから取得するBaseList
という項目のリストから始めました。また、3つの別個のリスト(ListA
,ListB
およびListC
)および各ピッカーの選択されたアイテム(SelectedA
,SelectedB
およびSelectedC
)を保存するための3つのリストを作成します。Xamarin.Formsで3つのピッカーの動的セットを作成する
private List<Item> BaseList;
private List<Item> _ListA;
private Item _SelectedA;
private List<Item> _ListB;
private Item _SelectedB;
private List<Item> _ListC;
private Item _SelectedC;
…
//Api Calls
private void LoadData()
{
…
BaseList = new List<Item> (ListFromWebServices);
_ListA = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListA));
_ListB = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListB));
_ListC = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListC));
}
…
//Public Fields
public List<Item> ListA
{
get
{
return _ListA;
}
}
public Item SelectedA
{
get
{
return _SelectedA;
}
set
{
SetProperty(ref _SelectedA, value, nameof(SelectedA));
}
}
public List<Item> ListB
{
get
{
return _ListB;
}
}
public Item SelectedB
{
get
{
return _SelectedB;
}
set
{
SetProperty(ref _SelectedB, value, nameof(SelectedB));
}
}
public List<Item> ListC
{
get
{
return _ListC;
}
}
public Item SelectedC
{
get
{
return _SelectedC;
}
set
{
SetProperty(ref _SelectedC, value, nameof(SelectedC));
}
}
このコードは、私たちのViewModelにあるので、選択した項目があるときはいつでも、私たちは、値を基準プロパティを設定し、ItemSource年代を更新するためにPropertyChangedEventArgs
INotifyPropertyChanged
から
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value,
[CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
を呼び出すようにするSetPropertyを使用します我々はSelectedA
、SelectedB
およびSelectedC
のセッターからOnSelectedItemChanged
と呼んだ。この方法では、ピッカーがそれを引き起こしたかを示す指標を受信:
private void OnSelectedItemChanged(int index)
{
Item CurrentA = SelectedA;
Item CurrentB = SelectedB;
Item CurrentC = SelectedC;
int i;
switch (index)
{
case 0:
_ListB = new List<Item> (BaseList);
_ListB.Remove(CurrentA);
_ListB.Remove(CurrentC);
OnPropertyChanged(nameof(ListB));
_ListC = new List<Item>(BaseList);
_ListC.Remove(CurrentA);
_ListC.Remove(CurrentB);
OnPropertyChanged(nameof(ListC));
i = ListB.IndexOf(CurrentB);
if (i > -1)
{
_SelectedB = ListB[i];
}
OnPropertyChanged(nameof(SelectedB));
i = ListC.IndexOf(CurrentC);
if (i > -1)
{
_SelectedC = ListC[i];
}
OnPropertyChanged(nameof(SelectedC));
break;
case 1:
_ListA = new List<Item>(BaseList);
_ListA.Remove(CurrentB);
_ListA.Remove(CurrentC);
OnPropertyChanged(nameof(ListA));
_ListC = new List<Item>(BaseList);
_ListC.Remove(CurrentA);
_ListC.Remove(CurrentB);
OnPropertyChanged(nameof(ListC));
i = ListA.IndexOf(CurrentA);
if (i > -1)
{
_SelectedA = ListA[i];
}
OnPropertyChanged(nameof(SelectedA));
i = ListC.IndexOf(CurrentC);
if (i > -1)
{
_SelectedC = ListC[i];
}
OnPropertyChanged(nameof(SelectedC));
break;
case 2:
_ListA = new List<Item>(BaseList);
_ListA.Remove(CurrentB);
_ListA.Remove(CurrentC);
OnPropertyChanged(nameof(ListA));
_ListB = new List<Item>(BaseList);
_ListB.Remove(CurrentA);
_ListB.Remove(CurrentC);
OnPropertyChanged(nameof(ListB));
i = ListA.IndexOf(CurrentA);
if (i > -1)
{
_SelectedA = ListA[i];
}
OnPropertyChanged(nameof(SelectedA));
i = ListB.IndexOf(CurrentB);
if (i > -1)
{
_SelectedB = ListB[i];
}
OnPropertyChanged(nameof(SelectedB));
break;
}
}
我々は基本的に電話をしてくれなかった2つのピッカーにBaseList
をコピーし、別の変数の各ピッカーの現在の選択項目を保存している、ここで何新しいリストのそれぞれの新しいリストで、他のピッカーが使用しているすべてのオプションを削除し、最初に選択したアイテムに新しいリストの選択したアイテムを再度設定し、最後にOnPropertyChanged()
を呼び出して変更のビューを通知します。
ここでの問題は、ピッカーでItemSource
を変更したときにSelectedItem
をnull
に設定することです。 OnSelectedItemChanged()
が呼び出された後にセッターにOnPropertyChanged()
を呼び出すと、一方のピッカーの無限ループがもう一方のピッカーを更新し、値を設定する前に値がヌルでないかどうかをチェックするフィルターを追加して、セット。