1

アップデート:

問題を明確に説明するデモをアップロードしました。こちらからダウンロードしてください

ListBoxの選択を処理するマネージャークラスを開発しています。(ListBoxが提供するデフォルトの選択機能では、要件を満たすことができません)

したがって、アイテムがリストボックスに追加されると、マネージャークラスは対応するリストボックスアイテムを取得し、それを選択または非選択にする必要があります。

新しく追加されたアイテムのいくつかの情報を伝える必要があると思いますが、 (異なるパラメーターで)複数回呼び出されItemContainerGenerator.ItemsChangedたときに同じイベント引数を提供するためListBox.Items.Add、非常に混乱します。新しく追加されたアイテムに対して新しく生成された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では、2つのアイテムがlistBoxに追加され、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

質問を完全に理解しているかどうかはわかりません。ただし、新しく作成されたListBoxItemを表示する前に一度操作する方法だけの場合は、派生ListBoxを作成して、PrepareContainerForItemOverrideメソッドをオーバーライドするだけで済みます。

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を使用できます。OnCollectionChangedNotifyCollectionChangedEventArgsNewItems

于 2013-01-09T15:08:00.490 に答える
0

多分カットサムリストボックスクラスを作成してメソッドをオーバーライドしますか?

 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 に答える