1

更新:

我上传了一个演示,试图清楚地解释我的问题。在这里下载。

我正在开发一个处理列表框选择的管理器类。(ListBox提供的默认选择功能不能满足我的要求)

因此,当一个项目添加到 ListBox 时,我的管理器类应该获取相应的 ListBoxItem并使其被选中或取消选中。

虽然我认为ItemContainerGenerator.ItemsChanged应该告诉新添加的项目的一些信息,但它在ListBox.Items.Add多次调用时提供相同的事件arg(使用不同的参数),这让我很困惑。谁能告诉我如何为新添加的项目获取新生成的 ListBoxItem。

演示问题的代码:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Button Content="Add two items" Click="Button_Click_1"/>
        <ListBox Name="listBox">
            <System:Int32>1</System:Int32>
            <System:Int32>2</System:Int32>
            <System:Int32>3</System:Int32>
        </ListBox>
    </StackPanel>
</Window>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        SelectionManager selectionManager = new SelectionManager();
        selectionManager.Join(listBox);
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        listBox.Items.Add(4);
        listBox.Items.Add(5);
    }
}

这里,在Button_Click 中,listBox 添加了两个item,selectionManager 应该同时获取ListBoxItem。

class SelectionManager
{
    public void Join(ListBox element)
    {
        element.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged;
    }

    private List<int> listBoxItemPendingJoinIndexes = new List<int>();

    void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
    {
        Contract.Requires(listBoxItemPendingJoinIndexes.Count > 0);
        ItemContainerGenerator generator = (ItemContainerGenerator)sender;
        if (generator.Status != GeneratorStatus.ContainersGenerated)
            return;
        generator.StatusChanged -= ItemContainerGenerator_StatusChanged;

        foreach (var index in listBoxItemPendingJoinIndexes)
        {
            ListBoxItem listBoxItem = (ListBoxItem)generator.ContainerFromIndex(index);
            Join(listBoxItem);
        }
        listBoxItemPendingJoinIndexes.Clear();
    }

    void ItemContainerGenerator_ItemsChanged(object sender, ItemsChangedEventArgs e)
    {
        ItemContainerGenerator generator = (ItemContainerGenerator)sender;
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                listBoxItemPendingJoinIndexes.Add(e.Position.Index
                      + e.Position.Offset);//same e.Position
                generator.StatusChanged += ItemContainerGenerator_StatusChanged;
                break;
        }

    }
}
4

3 回答 3

0

I'm not sure if i fully understand the question. But if it is only about how to manipulate a newly created ListBoxItem once before it is displayed, you could create a derived ListBox and just override the PrepareContainerForItemOverride method.

public class MyListBox : ListBox
{
    protected override void PrepareContainerForItemOverride(
        DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);

        var listBoxItem = element as ListBoxItem;
        ...
    }
}
于 2013-01-09T15:46:30.253 回答
0

如果您的项目来源是ObservableCollection,您可以使用OnCollectionChanged事件,它具有NotifyCollectionChangedEventArgs检查NewItems更改中涉及的新项目的列表。

于 2013-01-09T15:08:00.490 回答
0

也许创建一个cutsom列表框类并覆盖这些方法?

 public class SafeListBox : ListBox 
    { 
        delegate void insertDelegate(int i, object o); 

        public SafeListBox() 
        { 
            this.Items = new CustomObjectCollection(this); 
        } 

        public new CustomObjectCollection Items 
        { 
            get; 
            set; 
        } 

        public class CustomObjectCollection : ListBox.ObjectCollection 
        { 
            private ListBox listBox = null; 

            public CustomObjectCollection(ListBox listBox) : base(listBox) 
            { 
                this.listBox = listBox; 
            } 

            public new void Insert(int index, object item) 
            { 
                if (listBox.InvokeRequired) 
                { 
                    insertDelegate setTextDel = delegate(int i, object o) 
                    { 
                        base.Insert(i, o); 
                    }; 

                    try 
                    { 
                        listBox.Invoke(setTextDel, new object[] { index, item }); 
                    } 
                    catch 
                    { 
                    } 
                } 
                else 
                { 
                    base.Insert(index,item); 
                } 
            } 
        } 
    }
于 2013-01-09T15:09:03.560 回答