积极答复者
如何获取新添加到ListBox的元素的ListBoxItem?

问题
-
这个文件演示了我的问题:https://www.box.com/s/5gltokm5wreara2xg19k
我想要做一个类SelectionManager来控制项目的选取。
比如界面上有5个ToggleButton,把这5个ToggleButton让SelectionManager管理,SelectionManager.MaximunSelect=3,那么这5个ToggleButton只能同时选中3个。
又如,界面上3个CheckBox,又有一个ListBox,ListBox里有5个元素。把3个CheckBox和1个ListBox交由SelectionManager管理,SelectionManager.MaximunSelect=2。那么,这3个CheckBox和5个ListBox里的元素只能同时选中2个。可能1个CheckBox打勾,1个ListBoxItem选中。
再进一步,已经接受SelectionManager管理的ListBox可能又添加了2个元素,这时界面上有3个CheckBox,而ListBox里有7个元素,SelectionManager.MaximunSelect=2。新加入的元素也不能成为“法外之地”,这10个元素只能同时选中2个。
SelectionManager.Join(ToggleButton element), SelectionManager.Join(CheckBox element), SelectionManager.Join(ListBox element)分别令ToggleButton、CheckBox、ListBox受SelectionManager的管理,具体来说就是SelectionManager订阅它们的事件,然后设置他们选中或不选中。
public void Join(ListBox element) { element.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged; for (int i = 0; i < element.Items.Count; i++) { ListBoxItem listBoxItem = (ListBoxItem)element.ItemContainerGenerator.ContainerFromIndex(i); Join(listBoxItem);//SelectionManager已经可以管理listBoxItem了。 } }
上面的代码订阅了ItemsChanged事件,这个事件有参数ItemsChangedEventArgs。
如果ItemsChangedEventArgs.Action==Add,我本来以为e.Position.Index + e.Position.Offset就是新元素在ListBox.Items中的位置。我用了以下代码来测试
private void Window_Loaded_1(object sender, RoutedEventArgs e) { SelectionManager selectionManager = new SelectionManager(); selectionManager.MaximumSelected = 1; selectionManager.Join(toggleButton1); selectionManager.Join(toggleButton2); selectionManager.Join(toggleButton3); selectionManager.Join(toggleButton4); selectionManager.Join(listBox); } private void Button_Click_1(object sender, RoutedEventArgs e) { listBox.Items.Add(9); listBox.Items.Add(10); }
发现,Add(9)、Add(10)时,ItemsChangedEventArgs的各项属性都是相同的,于是我无法分辨9和10到底加到了ListBox.Items的什么位置,因此也无法用
ListBoxItem listBoxItem = (ListBoxItem)generator.ContainerFromIndex(index);
获得listBoxItem。
所以我想问下,我上面的思路对不对。如何调整代码,使得SelectionManager的使用者,不论用ListBox.Items.Add还是Insert,SelectionManager都能获得新加入的元素的ListBoxItem?
- 已编辑 爱让一切都对了 2013年1月10日 1:51
答案
-
我发现我思路错了。
WPF已经把功能和表现分开了,我要的是“限制选择数量”这个功能,应该用“限制选择数量控件”,而不是把本来“从一组项目中选择一个或多个”的ListBox改装成我要的控件。我又注意到RadioButton有GroupName属性,可以把几个RadioButton关联起来。
于是我创建了一个自定义控件LimitCheckBox,继承自ToggleButton(或许也可以继承自别的),新增GroupName属性、Checking事件。
另外加一个LimitCheckService类,有SetMaxSelection(string groupName, int n)方法。当设置LimitCheckBox.GroupName的时候,LimitCheckBox就告诉LimitCheckService,自己是哪一组的;LimitCheckService也订阅LimitCheckBox的Checking事件。
LimitCheckBox加CoerceCheck方法,方法里引发Checking事件。LimitCheckService收到事件就检查该组里IsChecked==true的有没有达到上限,有的话返回false,否则返回true。
ItemsControl可以和LimitCheckBox配合使用。
全部回复
-
我觉得你每当itemsChanged的时候, 你可以清空“SelectionManager”里面的ListBox,或者ListBOxItem,然后当元素加进去之后, 重新把这个ListBox加到里面。
Sheldon _Xiao
MSDN Community Support | Feedback to us
Develop and promote your apps in Windows Store
Please remember to mark the replies as answers if they help and unmark them if they provide no help. -
我发现我思路错了。
WPF已经把功能和表现分开了,我要的是“限制选择数量”这个功能,应该用“限制选择数量控件”,而不是把本来“从一组项目中选择一个或多个”的ListBox改装成我要的控件。我又注意到RadioButton有GroupName属性,可以把几个RadioButton关联起来。
于是我创建了一个自定义控件LimitCheckBox,继承自ToggleButton(或许也可以继承自别的),新增GroupName属性、Checking事件。
另外加一个LimitCheckService类,有SetMaxSelection(string groupName, int n)方法。当设置LimitCheckBox.GroupName的时候,LimitCheckBox就告诉LimitCheckService,自己是哪一组的;LimitCheckService也订阅LimitCheckBox的Checking事件。
LimitCheckBox加CoerceCheck方法,方法里引发Checking事件。LimitCheckService收到事件就检查该组里IsChecked==true的有没有达到上限,有的话返回false,否则返回true。
ItemsControl可以和LimitCheckBox配合使用。