0

私はいくつかのアイテムにListBox縛られObservableCollectionています。それらは、基本クラスまたはいくつかの継承されたクラスのインスタンスである可能性があります。アイテム リストを 3 秒に 1 回更新する必要があります。コレクション リスト アイテム プロバイダーを更新するには、新しいリストをダウンロードしてから、古いリストと新しいリストをマージする必要があります。古いリストと新しいリストのアイテムは、Item.Idプロパティを使用して関連付けられます。問題は、ちらつきなしでリストボックス内のアイテムを更新し、現在の選択を保持する方法などです。

それには2つの方法があります

  1. list.RemoveAt()その後list.InsertAt()、すべてのアイテムを交換します。CollectionViewSource.DeferRefresh()また、更新前に現在の選択を使用して保存し、後で復元すると便利です。このアプローチでは、ツールチップのちらつきなどの問題が発生しました。

  2. もう 1 つの方法は、古いアイテムの各プロパティを新しい値で更新することです。しかし、コレクションには継承されたインスタンスがいくつかあるため、これはちょっと難しいです。

このような状況を処理する適切な方法は何ですか? ライブ データ更新を効率的に実装する方法 (更新が新しいインスタンス コレクションにダウンロードされる場合)?

4

2 に答える 2

0

PropertyChanged と CollectionChanged への呼び出しの数を制限する必要があります。

プロパティを更新し、新しい値 == old を確認し、そうであれば NotifyPropertyChanged を呼び出さないでください

クラスが一致しない場合は、2 つの UI 通知であるため、挿入を削除しないでください。
新しいアイテムを割り当てるだけです。アイテム[4] = 新しいアイテム。

仮想化を使用していますか。
アイテムが表示されない場合は、UI が更新されません。

以下をご覧ください。1 つまたは複数のアイテムが更新された以外に、UI のちらつきがありません。PropertyChanged を適切に利用していないと思われます。

<Window x:Class="ListViewUpdate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource self}}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Button Content="Add10000" Click="Button_Click"/>
            <Button Content="UpdateFirst" Click="Button_Click_1"/>
            <Button Content="UpdateLast" Click="Button_Click_2"/>
            <Button Content="ReplaceFirst" Click="Button_Click_3" />
            <Button Content="UpdateAll" Click="Button_Click_4"/>
        </StackPanel>
        <ListView Grid.Row="1" ItemsSource="{Binding Path=Persons}" DisplayMemberPath="Name" />
    </Grid>
</Window>

namespace ListViewUpdate
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<Person> persons = new ObservableCollection<Person>();
        public MainWindow()
        {
            InitializeComponent();
        }
        public ObservableCollection<Person> Persons { get { return persons; } }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            for (UInt16 i = 0; i < 10000; i++)
            {
                Persons.Add(new Person(Guid.NewGuid().ToString()));
            }
            System.Diagnostics.Debug.WriteLine("");
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (Persons.Count == 0) return;
            for (UInt16 i = 0; i < UInt16.MaxValue; i++)
            {
                Persons[0].Name = Guid.NewGuid().ToString();
            }
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            if (Persons.Count == 0) return;
            int last = Persons.Count - 1;
            for (UInt16 i = 0; i < UInt16.MaxValue; i++)
            {
                Persons[last].Name = Guid.NewGuid().ToString();
            }
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            if (Persons.Count == 0) return;
            for (UInt16 i = 0; i < UInt16.MaxValue; i++)
            {
                Persons[0] = new Person(Guid.NewGuid().ToString());
            }
        }

        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            foreach (Person p in Persons) p.Name = Guid.NewGuid().ToString();
        }
    }
    public class Person: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        private string name;
        public string Name 
        {
            get { return name; }
            set
            {
                if (name == value) return;
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
        public Person(string name) { Name = name; }
    }
}
于 2012-10-09T15:46:42.630 に答える
0

どのように実装しても、常にリストボックス全体が更新されます。リストボックスのさまざまな方法の問題ではなく、リストボックスがリスト内のアイテムをどのように描画するかです。

リストボックスをサブクラス化し、その onpaint イベントをオーバーライドし、より効率的なコードを記述してちらつきをなくす必要がある場合があります。

私は過去に ListView http://www.codeproject.com/Articles/3617/Flicker-free-ListView-in-NET-Part-2 このコードを使用してそうしました。

これは、ちらつきのないリストボックスの開発にも役立つかもしれません。

于 2012-10-09T15:49:01.093 に答える