none
如何获取新添加到ListBox的元素的ListBoxItem? RRS feed

  • 问题

  • 这个文件演示了我的问题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月9日 16:10

答案

  • 我发现我思路错了。

    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配合使用。


    2013年1月12日 15:00

全部回复

  • 我觉得你每当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.

    2013年1月10日 7:52
    版主
  • 我发现我思路错了。

    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配合使用。


    2013年1月12日 15:00