WPF更新进度条却使数据集,全部采用接收 [英] Update WPF progress bar while filling DataSet, all using Rx

查看:331
本文介绍了WPF更新进度条却使数据集,全部采用接收的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点新的RX,所以请原谅我,如果这似乎愚蠢或明显...

I'm a bit new in Rx, so please excuse me if this seems silly or obvious...

我有一个应用程序,它在一定的时间,是指以扫描一个选定的文件夹,并检索递归的所有文件,之后,它需要将它们存储在数据库中。我想在这个过程中显示进度条,同时保持用户界面响应课程。 。取消按钮也将是不错在后一阶段

I have an application which at a certain time, is meant to scan a selected folder and retrieve all files recursively, after which it needs to store them in a database. I would like to display a progress bar during that process while keeping the UI responsive of course. A cancel button would also be nice at a later stage.

我实现了这一点使用RX,像这样:

I've implemented this using Rx, like so:

// Get a list of all the files
var enumeratedFiles = Directory.EnumerateFiles(targetDirectory, "*.*", SearchOption.AllDirectories);

// prepare the progress bar
            double value = 0;
            progBar.Minimum = 0;
            progBar.Maximum = enumeratedFiles.Count();
            progBar.Value = value;
            progBar.Height = 15;
            progBar.Width = 100;
            statusBar.Items.Add(progBar);

var files = enumeratedFiles.ToObservable()
                .SubscribeOn(TaskPoolScheduler.Default)
                .ObserveOnDispatcher()
                .Subscribe(x =>
                    {
                        myDataSet.myTable.AddTableRow(System.IO.Path.GetFileNameWithoutExtension(x));
                        value++;
                    },
                    () =>
                    {
                        myDataSetTableAdapter.Update(myDataSet.myTable);
                        myDataSetTableAdapter.Fill(myDataSet.myTable);
                        statusBar.Items.Remove(progBar);
                    });



然而,在上面的例子中的用户界面被锁定,并且进度条的过程中不更新。我想那是因为AddTableRow方法是阻塞线程,虽然我认为SubscribeOn(TaskPoolScheduler)应该运行在一个新的线程中的任务?

However, with the above example the UI is locked and the progress bar doesn't update during the process. I assume that's because the AddTableRow method is blocking the thread, although I believed that the SubscribeOn(TaskPoolScheduler) was supposed to run the task on a new thread?

我已经尝试了几种不同的方法为好,结果各不相同。例如增加了。做一行:

I've tried a few different approaches as well, with varying results. For example adding a .Do line:

var files = enumeratedFiles.ToObservable()
                .Do(x => myDataSet.myTable.AddTableRow(System.IO.Path.GetFileNameWithoutExtension(x)))
                .SubscribeOn(TaskPoolScheduler.Default)
                .ObserveOnDispatcher()
                .Subscribe(x =>
                    {
                        value++;
                    },
                    () =>
                    {
                        myDataSetTableAdapter.Update(myDataSet.myTable);
                        myDataSetTableAdapter.Fill(myDataSet.myTable);
                        statusBar.Items.Remove(progBar);
                        btnCancel.Visibility = Visibility.Collapsed;
                    });

这实际显示进度条的更新,并且UI没有完全锁定,但它是波涛汹涌和性能爬下来...

this actually shows the progress bar updates, and the UI is not completely locked but it is choppy and the performance crawls down...

我使用的是BackgroundWorker的做同样的工作,尝试过,但性能比之上(例如,对于接收的方式方法更糟糕21000文件的接收方式需要几秒钟,而BackgroundWorker的几分钟来完成)。

I've tried using a BackgroundWorker to do the same job, but the performance is way worse than the Rx approach above (for example, for 21000 files the Rx approach takes a few seconds while the BackgroundWorker a few minutes to finish).

我也看到了与代表们正在解决的进度条的ValueProperty类似的问题的方法,但我真的想如果可能的话,解决这个使用接收。

I've also seen similar problems being tackled with Delegates for the progress bar's ValueProperty method, but I would really like to solve this using Rx if possible.

我在这里丢失了一些东西明显?任何建议将高度赞赏...

Am I missing something obvious here? Any suggestion would be highly appreciated...

推荐答案

我已经找到了解决办法,并多一点细节是怎么回事

I've found the solution, and a bit more details on what's going on:

的延迟,而在调试模式中插入我提到的DataSet中的行只在那里,而当没有调试运行应用程序并不表明延迟和进度酒吧和项目的数量被处理快许多倍。傻我没有测试早...

The delay while inserting the rows in the DataSet I mentioned is only there in Debug mode, whereas when run without Debug the application doesn't show that delay and the progress bar and number of items are processed many times faster. Silly me for not testing that earlier...

虽然扫描文件递归有轻微的延迟(21000文件几秒钟),但因为它只是发生在你第一次做的是,我没有在我随后的测试注意到它,我只是专注于似乎慢了我的部分:DataSet的灌装。我想这Directory.EnumerateFiles缓存在内存中的一切,所以任何其他尝试读取相同的文件瞬间完成?

While scanning for the files recursively there is a slight delay (a few seconds for 21000 files) but since it only happens the first time you do that, I failed to notice it in my subsequent tests and I was only focusing on the part that seemed slow to me: the filling of the DataSet. I guess that Directory.EnumerateFiles caches everything in memory so any other attempt to read the same files completes instantly?

此外,似乎myDataSetTableAdapter.Fill(myDataSet.myTable 。也没必要)线,因为.Update方法已经保存在数据库本身的内容

Also, it seems that the myDataSetTableAdapter.Fill(myDataSet.myTable) line is not needed, since the .Update method already saves the contents in the database itself.

这是为我工作的最后的代码片段如下:

The final code snippet that worked for me is the following:

progBar.Height = 15;
progBar.Width = 100;
progBar.IsIndeterminate = true;
statusBar.Items.Add(progBar);

var files = Directory.EnumerateFiles(targetDirectory, "*.*", SearchOption.AllDirectories)
            .Where(s => extensions.Contains(System.IO.Path.GetExtension(s))) // "extensions" has been specified further above in the code
            .ToObservable(TaskPoolScheduler.Default)
            .Do(x => myDataSet.myTable.AddTableRow(System.IO.Path.GetFileNameWithoutExtension(x), x, "default")) // my table has 3 columns
            .TakeLast(1)
            .Do(_ => myDataSetmyTableTableAdapter.Update(myDataSet.myTable))
            .ObserveOnDispatcher()
            .Subscribe(xy =>
                {
                    //progBar.Value++; //commented out since I've switched to a marquee progress bar
                },
                () =>
                {
                    statusBar.Items.Remove(progBar);
                    btnCancel.Visibility = Visibility.Collapsed;
                });

这似乎是所有帮助球员工作对我很好,谢谢!

This seems to work fine for me, thanks for all the help guys!

编辑:我已经进一步扩大了上面,包括一个取消按钮功能。如果用户点击了取消按钮,则处理立即停止。我试图保持它作为优雅越好,所以我已经添加了从取消按钮的Click事件可观察到的,然后用来.TakeUntil上面可观察现有的文件。现在,该代码如下所示:

edit: I've further expanded the above, to include a Cancel button functionality. If the user clicks on the Cancel button, the process is stopped immediately. I've tried to keep it as elegant as possible, so I've added an Observable from the Click event of the Cancel button, then used .TakeUntil in my existing files Observable above. The code now looks like this:

// Show the Cancel button to allow the user to abort the process
btnCancel.Visibility = Visibility.Visible;

// Set the Cancel click event as an observable so we can monitor it
var cancelClicked = Observable.FromEventPattern<EventArgs>(btnCancel, "Click");

// Use Rx to pick the scanned files from the IEnumerable collection, fill them in the DataSet and finally save the DataSet in the DB
var files = Directory.EnumerateFiles(targetDirectory, "*.*", SearchOption.AllDirectories)
            .Where(s => extensions.Contains(System.IO.Path.GetExtension(s)))
            .ToObservable(TaskPoolScheduler.Default)
            .TakeUntil(cancelClicked)
            .Do(x => ....

这篇关于WPF更新进度条却使数据集,全部采用接收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆