C#使用List實現類似RadioButtonGroup的單選功能
首先說說需求,有多種不同類型的UserControl用於以不同的方式顯示數據,想通過在另一個view中實現某種點擊選中按鈕後,在數據顯示view中,只讓被邏輯關聯的UserControl顯示(Visiable),其他UserControl全部折疊(Collasped)起來。這種方式就類似於幾個控件綁定到一組RadioButtonGroup中,哪個RadioButton被選中了,就顯示哪部分內容。
雖然我知道有種修改template的方式,應該可以做到,但我還沒深入學習到這部分。於是想了個別的招。
因為是在不同的View上,如此一來,就不能簡單地通過綁定到元素的IsSelected->Visilibity的方式來實現。
那麽就自己實現一個類似於RadioButtonGroup的功能。
1.首先準備一個類,用於和我的UserControl的Visilibity屬性綁定。
public class IsSelectedClass { protected bool isSelected; public bool IsSelected
{
get=>isSelected; set { isSelected = value; OnPropertyChanged(nameof(IsSelected)); } }}
2.準備一個GroupList,用於存儲我們加入(Add)的IsSelectedCalss對象
List<IsSelectedCalss> list = new List<IsSelectedCalss>();
3.為了有更好的擴展性和兼容性,接下來將IsSelectedCalss和List<IsSelectedCalss>重新封裝為泛型形式
並且,因為IsSelected屬性與UserControl的Visibility屬性進行綁定,所以要實現INotifyPropertyChanged接口。
我們將RadioGroupList類視為RadioButtonGroup類,往RadioGroupList對象中添加的是繼承自IsSelectedClass類的對象。
並且在將IsSelectedClass類對象添加進List的時候,訂閱其PropertyChanged事件,這樣我們可以在該對象的IsSelected屬性值改變時收到通知,然後再處理List中的其他IsSelectedClass對象。
記得在Remove掉該對象時,要取消訂閱該事件。即使這對性能影響不大,而且Remove也不常用,但對內存有一個良好的規劃,是一個程序員基本的素養。
1 public class IsSelectedClass : INotifyPropertyChanged 2 { 3 protected bool isSelected; 4 public virtual bool IsSelected 5 { 6 get =>isSelected; 7 set 8 { 9 isSelected = value; 10 OnPropertyChanged(nameof(IsSelected)); 11 } 12 } 13 public event PropertyChangedEventHandler PropertyChanged; 14 15 [NotifyPropertyChangedInvocator] 16 protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 17 { 18 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 19 } 20 21 public void SetSelectedTrue() 22 { 23 this.isSelected = true; 24 } 25 } 26 27 public class RadioGroupList<T> where T : IsSelectedClass 28 { 29 List<T> list = new List<T>(); 30 31 public void AddRadioSelector(T t) 32 { 33 list.Add(t); 34 t.PropertyChanged += TSelectedPropertyChangedEventHandler; 35 36 } 37 38 private void TSelectedPropertyChangedEventHandler(object sender, PropertyChangedEventArgs e) 39 { 40 var t = sender as IsSelectedClass; 41 if (e.PropertyName == nameof(t.IsSelected)) 42 { 43 if (t.IsSelected) 44 { 45 for (int i = 0; i < list.Count; i++) 46 { 47 list[i].IsSelected = false; 48 } 49 t.SetSelectedTrue(); 50 } 51 } 52 } 53 54 public void RemoveSelector(T t) 55 { 56 if (list.Contains(t)) 57 { 58 list.Remove(t); 59 t.PropertyChanged -= TSelectedPropertyChangedEventHandler; 60 } 61 } 62 }關鍵代碼
4.為了改進RadioGroupList<T>類的使用,添加幾個類似於List的常用方法和索引器。
public void AddRangeSelector(T[] t) { foreach (var VARIABLE in t) { AddRadioSelector(VARIABLE); } } public void Clear() { foreach (var VARIABLE in list) { VARIABLE.PropertyChanged -= TSelectedPropertyChangedEventHandler; } list.Clear(); } public T this[int index] => list[index];
5.簡單測試性能
因為重復遍歷了List中的元素兩次,所以,我生成了200個對象來測試其性能,看看這種做法會不會卡死界面。
public ShellViewModel()//構造函數,沒什麽好說的 { RadioGroupList<IsSelectedClass> islist = new RadioGroupList<IsSelectedClass>(); int tcount = 200;//控制循環生成對象的數目 for (int i = 0; i < tcount; i++) { islist.AddRadioSelector(new IsSelectedClass()); } islist[110].IsSelected = true; islist[111].IsSelected = true; islist[138].IsSelected = true; islist[198].IsSelected = true; for (int i = 0; i < tcount; i++) { Console.WriteLine($"{i}={islist[i].IsSelected}"); } }
最終的輸出結果是,只有索引為198的值為True,其他全為False。而且程序執行得很快,幾乎是啟動的時候就顯示出來了。
沒用Timer測試,是因為,這個是給控件用的,我的控件最多也不超過10個,所以性能上足夠用了。
雖然這個功能很簡單,但我作為一個小菜鳥,還是蠻開心的。歡迎大家多多留言交流~
RadioGroupList<T>
C#使用List實現類似RadioButtonGroup的單選功能