【问题标题】:How to update ListBox when ObservableCollection items changed?ObservableCollection 项目更改时如何更新 ListBox?
【发布时间】:2013-12-15 14:34:31
【问题描述】:

我有一个测试应用程序,它在循环中向 ListBox 添加项目。现在,当所有项目都添加到 ObservableCollection 时,ListBox 会更新。添加每个项目时,我需要更新 ListBox。请帮助俄罗斯人=)

这是我的代码:

MainWindow.xaml

<Grid>
    <Button Content="Button" HorizontalAlignment="Left" Margin="432,288.04,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <ListBox x:Name="urlsListBox" ItemsSource="{Binding Urls}" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="417"/>
</Grid>

MainWindow.xaml.cs

/// <summary>
/// Логика взаимодействия для MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    ViewModel model = new ViewModel();

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = model;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        model.GetUrls();
    }
}

ViewModel.cs

class ViewModel
{
    public ObservableCollection<Url> Urls { get; set; }

    public ViewModel()
    {
        Urls = new ObservableCollection<Url>();
    }

    public void GetUrls()
    {
        for (int i = 0; i < 5; i++)
        {
            Urls.Add(new Url { link = i.ToString() });
            //Thread.Sleep(300);
        }
    }
}

public class Url
{
    public string link { get; set; }
}

【问题讨论】:

  • 我点击按钮,5 个项目被添加到ListBox,你不会发生这种情况吗?
  • 您是否考虑过在您的收藏中实施 INotifyPropertyChanged?

标签: c# wpf xaml listbox


【解决方案1】:

我认为您需要在每次添加新项目时通知 UI 可观察的 URL 集合中发生的更改。

如果您在视图模型中实现了 INotifyPropertyChanged,则注册可观察集合,其中发生任何更改。

private ObservableCollection<Url> _urls; 
public ObservableCollection<Url> Urls 
{ get
  { 
    return _urls;
  } 
  set
  {
    _urls = value;
    OnPropertyModified("Urls");
  }
}

【讨论】:

    【解决方案2】:

    我猜你想要 UI to update on every item addition 收藏。

    查看Thread.Sleep(300),我假设您要等待 300 毫秒,然后再将另一个项目添加到集合中。

    DispatcherTimer 就是你要找的东西。此示例将起作用:

    public void GetUrls()
    {
        DispatcherTimer timer = new DispatcherTimer();
        timer.Interval = new TimeSpan(0, 0, 0, 0, 300);
        int i = 0;
        timer.Tick += (s, e) =>
           {
               Urls.Add(new Url { link = i.ToString() });
               ++i;
               if (i == 5)
                 timer.Stop();
           };
        timer.Start();
    }
    

    这将在每 300 毫秒后将项目添加到集合中,一旦项目计数达到 5,将停止计时器。


    就像我在评论中提到的那样

    与 UI 线程关联的调度程序可以一次处理一个操作 时间。将项目添加到集合时,无法处理渲染 同时操作。因此 GUI 没有得到刷新。 DispatcherTimer 的使用为渲染操作提供了一些时间来处理。

    没有DispatcherTimer 的另一种方法是使用enqueue empty delegate on UI dispatcher with Render priority,这样所有优先级高于渲染(包括渲染)的操作都会在移动到添加集合中的另一个项目之前得到处理。

    public void GetUrls()
    {
        for (int i = 0; i < 5; i++)
        {
            Urls.Add(new Url { link = i.ToString() });
            App.Current.Dispatcher.Invoke((Action)(() => { }),
                                                   DispatcherPriority.Render);
        }
    }
    

    【讨论】:

    • 这是可行的,但不是我真正需要的。我使用 Thread.Sleep(300) 来模拟长时间工作的操作。我现在不知道它会得到多少时间。我想我需要使用 Task,但我的尝试没有成功 =(
    • 你的问题很不清楚。您说您想在每次添加时更新 UI(正是我在回答中提供的内容)。您必须解释更多您正在寻找的内容。你需要定义what actually you need。
    • 我需要在每次添加时更新 UI。但是在您的示例中,您使用计时器来更新集合。我不想使用计时器,因为我不需要它。有没有其他方法可以在没有计时器的情况下更新 UI?
    • 与 UI 线程关联的调度程序一次只能处理一个操作。将项目添加到集合时,不能同时处理渲染操作。因此 GUI 没有得到刷新。这就是我使用 DispatcherTimer 以便渲染操作有时间处理的原因。您可以将时间跨度设置为某个较低的值,例如 50 毫秒,以防添加之间的时间过长。
    • 好的,感谢您的帮助!但我会继续研究这个问题。
    猜你喜欢
    • 2011-07-14
    • 2017-11-19
    • 2014-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多