簡體   English   中英

在Xamarin.Forms上動態設置3個選擇器

[英]Making a dynamic set of 3 pickers on Xamarin.Forms

我們正在Xamarin.Forms上開發跨平台應用程序。
在其中一個頁面上,我們需要顯示一組具有相同項目列表的3個選擇器。 這個想法是,當您在一個選擇器中選擇一個項目時,該項目將從其他兩個項目的項目來源中刪除。
為此,我們開發了以下代碼:
我們從一個從Web服務獲得的稱為BaseList的項目列表開始。 我們還創建了3個單獨的列表( ListAListBListC )和3個項目,以存儲每個選擇器的選定項目( SelectedASelectedBSelectedC )。

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上,因此我們使用SetProperty將引用的屬性設置為該值,並從INotifyPropertyChanged調用PropertyChangedEventArgs

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));
}

為了更新ItemSource的內容,無論何時更改選定的項目,我們都會從SelectedASelectedBSelectedC的設置器中調用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;
    }
}

我們在這里所做的基本上是將每個選擇器的當前所選項目保存在單獨的變量中,將BaseList復制到未調用該事件的兩個選擇器中,然后在每個新列表上刪除其他選擇器正在使用的所有選項,將每個新列表上的選定項目再次設置為最初選擇的項目,最后調用OnPropertyChanged()通知更改的視圖。

這里的問題是,當我們在ItemSource上更改ItemSource時, ItemSource SelectedItem設置為null 在調用OnSelectedItemChanged()之后在設置器上調用OnPropertyChanged()導致一個選擇器更新另一個的無限循環,並添加一個過濾器以檢查該值是否不為null,然后再設置該設置,使選擇器不顯示任何選定的項目,而該值已設置。

以防萬一有人遇到相同的問題,我們為此找到了解決方案。 證明是否使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));

有用。 我們不知道為什么

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM