2017-09-26 4 views
1

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を使用します我々はSelectedASelectedBおよび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を変更したときにSelectedItemnullに設定することです。 OnSelectedItemChanged()が呼び出された後にセッターにOnPropertyChanged()を呼び出すと、一方のピッカーの無限ループがもう一方のピッカーを更新し、値を設定する前に値がヌルでないかどうかをチェックするフィルターを追加して、セット。

答えて

0

誰かが同じ問題を抱えている場合に備えて、私たちはこれに対する解決策を見つけました。あなたがCurrentACurrentBCurrentCグローバル変数を作成し、それぞれのケースにif ((CurrentA != SelectedA) && (!(SelectedA is null))) { ... (do all the stuff) } break;を追加し、最後にあなたが

_SelectedA = CurrentA; 
OnPropertyChanged(nameof(SelectedA)); 
_SelectedB = CurrentB; 
OnPropertyChanged(nameof(SelectedB)); 
_SelectedC = CurrentC; 
OnPropertyChanged(nameof(SelectedC)); 

を設定した場合、それは動作しますが判明。私たちはなぜthoを知りません:)

関連する問題