0

我有ListBox一些ObservableCollection项目。它们可能是基类或某些继承类的实例。我需要在 3 秒内更新一次项目列表。要更新集合列表项提供者下载新列表,然后我需要合并新旧列表。新旧列表中的项目使用Item.Id属性关联。问题是如何在不闪烁的情况下更新列表框中的项目并保留当前选择等。

有两种方法可以做到这一点

  1. list.RemoveAt()然后list.InsertAt()更换所有项目。CollectionViewSource.DeferRefresh()在更新和恢复之前使用和保存当前选择也很有用。使用这种方法,我遇到了一些问题,例如工具提示闪烁等。

  2. 另一种方法是用新值更新旧项目的每个属性。但这有点困难,因为集合中有一些继承的实例。

处理这种情况的正确方法是什么?如何有效地实现实时数据更新(在新实例集合中下载更新时)?

4

2 回答 2

0

无论您如何实现它,它总是会刷新整个列表框。这不是列表框不同方法的问题,而是列表框如何绘制列表中的项目。

您可能必须对列表框进行子类化并覆盖其 onpaint 甚至编写更高效的代码以使其无闪烁。

我过去在 ListView http://www.codeproject.com/Articles/3617/Flicker-free-ListView-in-NET-Part-2上 使用此代码这样做过。

可能这也有助于开发无闪烁列表框。

于 2012-10-09T15:49:01.093 回答
0

需要限制对 PropertyChanged 和 CollectionChanged 的​​调用次数。

更新属性并检查新值 == 旧,如果是,请不要调用 NotifyPropertyChanged

如果它不是类匹配,则不要删除插入,因为这是两个 UI 通知。
只需分配新项目。项目[4] = 新项目。

您是否使用虚拟化。
如果该项目未显示,那么我很漂亮 UI 不会刷新。

请看下文。除了更新的一个或多个项目之外,我没有任何 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 回答