更新列表框异步winforms

时间:2016-10-17 12:34:25

标签: c# winforms listbox reactive-programming

我想在ListBox中插入很多元素,我可以获得尽可能多的响应。为此我设置了一个生成string s的生成器。我想在100毫秒窗口中添加新项目,而不是阻止UI并使用某种任务池(在当前情况下为Scheduler.Default)。

Reactive浮现在我的脑海中,因为它符合每一项要求。

// Use binding, rather than control.Items.Add, so the elements can be added on simultanious tasks, without working on the Form's thread.
private readonly BindingList<string> elements = new BindingList<string>();

private void button1_Click(object sender, EventArgs e)
{
    BindingSource source = new BindingSource {DataSource = elements};
    listBox1.DataSource = source;
    // works, but this way the window is useless.
    //listBox1.BeginUpdate();
    // generates 500 items to add into the listbox
    Observable.Generate(0L, x => x < 500, x => x + 1,
        y => "Current thread : " + Thread.CurrentThread.ManagedThreadId) // show which thread the item is generated
        .Window(TimeSpan.FromSeconds(0.1d)) // supposedly makes UI unblock every 100 millisec
        .ObserveOn(Scheduler.Default) // supposedly generate elements on the "thread pool"
        .Subscribe(
            x =>
            {
                x.Subscribe(s => elements.Add(s));
            } /* , () =>
            {
                // for this we need System.Reactive.Windows.Forms
                ControlScheduler scheduler = new ControlScheduler(this);
                scheduler.Schedule(TimeSpan.FromSeconds(0L), () => listBox1.EndUpdate());
            } */);
}

我的问题是,它为每一行显示相同的线程ID。因此,Scheduler.Default上不会生成元素。我希望能够每100毫米改变焦点,但不能正常工作。

修改

我也尝试过后台工作者方法

private void button2_Click(object sender, EventArgs eventArgs)
{
    // tried with elements volatile.
    BindingSource source = new BindingSource {DataSource = elements};
    listBox1.DataSource = source;
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    Observable.Generate(0L, x => x < 500, x => x + 1,
        y => "Current thread : " + Thread.CurrentThread.ManagedThreadId)
        .Window(TimeSpan.FromSeconds(0.1d))
        .ObserveOn(Scheduler.Default)
        .Subscribe(
            window =>
            {
                window.Subscribe(s => elements.Add(s),
                    () => backgroundWorker1.ReportProgress(1)
                    );
            });
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // doesn't work. No elements showing. Something must be notified, but couldn't make it working
    listBox1.Refresh();
}

这种方法差别不大,只需要后台工作者的样板代码,并保证不会阻止UI。

0 个答案:

没有答案