在操作完成之前,UI不响应 [英] UI unresponsive until action is complete
问题描述
我不确定标题是否很好地说明了此问题.本质上,我所拥有的是一个WinForm应用程序,该应用程序将从文件夹中的文件列表检索到ListView中,然后单击一个按钮以通过FTP将其上传到远程服务器.
I'm not sure if the Title is a good description of this issue or not. Essentially what I have is a WinForm app that retrieves a list of files from a folder into a ListView, then a button is clicked to upload them via FTP to a remote server.
从功能上讲,该应用程序可以按预期运行:
Functionally speaking, the app works as expected:
- 打开应用
- 在ListView控件中查看文件列表
- 点击上传"按钮
- ListView中列出的文件已上传;每次成功上传后,ListView都会更新为显示 成功"
- 所有文件上传后,操作停止.
- Open app
- Review list of files in ListView control
- Click Upload button
- Files listed in ListView are uploaded; after each successful upload the ListView is updated to show 'Success'
- After all files are uploaded, operation stops.
我的问题是,单击上传按钮后,UI几乎没有响应,直到操作完成.每个文件上传后,ListView都会按预期更新,甚至可以使活动行保持焦点.这是处理文件的for循环.有一点背景-在下面的代码摘录中,每个for ... loop处理2个文件-主文件是ListView中显示的唯一文件.每个循环中的第二个文件是一个触发文件,该文件在其主要文件发送后即发送.即:.primary,.trigger.两个文件都必须发送才能注册成功.如果主文件没有相应的触发文件,则在ListView中将无法使用该文件进行上传.
My issue is, after clicking the upload button the UI is pretty much unresponsive until the operation finishes. The ListView updates as expected as each file is uploaded and even keeps the active row in focus. Here is the for loop that processes the files. A little background - in the code excerpt below, each for...loop processes 2 files - the primary file is the only one that shows in the ListView. The 2nd file in each loop is a trigger file that is sent after its primary is sent, ie: .primary, .trigger. Both files have to send in order to register a success. If a primary file does not have a corresponding trigger file, it won't be available in the ListView for upload.
foreach (ListViewItem item in lvSourceFiles.Items)
{
int rowIndex = item.Index;
string fileName = item.SubItems[2].Text;
lvSourceFiles.EnsureVisible(rowIndex);
transferStatus = "Failed"; // Set this as a default
// Transfer the source file first
transferResult = session.PutFiles(readyFile, destFile, false, transferOptions);
// Throw on any error
transferResult.Check();
// If the source file transfer was successful, then transfer the trigger file
if (transferResult.IsSuccess)
{
transferResult = session.PutFiles(triggerFile, destFile, false, transferOptions);
transferResult.Check();
if (transferResult.IsSuccess)
{
transferStatus = "Success";
}
}
UpdateResultsToListView(lvSourceFiles, rowIndex, fileName, transferStatus);
}
是这种情况下,我需要实现某种异步功能,还是有更好的方法来执行此操作,以使UI在上载过程中不会冻结?本质上,我希望能够在上载运行时与表单进行交互,例如具有取消按钮来停止上载.就目前而言,在作业完成或终止应用程序之前,我无法对表单进行任何操作.
Is this a situation where I need to implement some sort of asynchronous functionality, or is there a better way to do this so the UI doesn't freeze during the upload process? Essentially I want to be able to interact with the form while the upload is running, such as having a cancel button to stop the upload. As it stands, I can't do anything with the form until the job completes, or I terminate the app.
谢谢, 詹姆斯
推荐答案
You could offload the long-running operation to a ThreadPool
thread, by using async/await and the handy Task.Run
method:
transferResult = await Task.Run(() => session.PutFiles(readyFile, destFile, false, transferOptions));
...并且:
transferResult = await Task.Run(() => session.PutFiles(triggerFile, destFile, false, transferOptions));
您还应该添加 async
修饰符在事件处理程序中,以便启用
You should also add the async
modifier in the event handler, in order to enable the await
operator.
重要:避免在卸载的方法中执行任何与UI相关的操作.如果要在操作过程中与UI通信,例如 Progress<T>
类.
Important: Avoid doing anything UI related in the offloaded method. If you want to communicate with the UI during the operation, for example for progress reporting, use the Progress<T>
class.
这篇关于在操作完成之前,UI不响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!