C# 使用Wait运行耗时任务时UI被阻止
我想建立一个文件夹清理程序。预计它将实时向C# 使用Wait运行耗时任务时UI被阻止,c#,wpf,multithreading,C#,Wpf,Multithreading,我想建立一个文件夹清理程序。预计它将实时向文本框控件报告已删除的文件。所以我在我的按钮点击事件中使用了wait Task.Run(()=>CleanFolder(folderPath,progress))函数。但是UI在运行时被阻塞。当CheanFolder()方法运行完成后,所有已删除的文件将同时显示 namespace FolderCleaner { public partial class MainWindow : Window { string folde
文本框
控件报告已删除的文件。所以我在我的按钮点击事件中使用了wait Task.Run(()=>CleanFolder(folderPath,progress))
函数。但是UI在运行时被阻塞。当CheanFolder()
方法运行完成后,所有已删除的文件将同时显示
namespace FolderCleaner
{
public partial class MainWindow : Window
{
string folderPath;
string matchPattern;
private void ButtonOpen_Click(object sender, RoutedEventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog() { Description = "Select a folder" };
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
textBoxPath.Text = folderPath;
buttonClean.IsEnabled = true;
textBoxList.Text = "Folder path: " + folderPath + "\n";
}
}
private async void ButtonClean_Click(object sender, RoutedEventArgs e)
{
matchPattern = textBoxPattern.Text;
buttonOpen.IsEnabled = false;
buttonClean.IsEnabled = false;
Progress<string> progress = new Progress<string>(msg =>
{
textBoxList.AppendText("File deleted: " + msg + "\n");
textBoxList.CaretIndex = textBoxList.Text.Length;
textBoxList.ScrollToEnd();
});
try
{
await Task.Run(() => CleanFolder(folderPath, progress));
textBoxList.AppendText("Mission complete!");
textBoxList.CaretIndex = textBoxList.Text.Length;
textBoxList.ScrollToEnd();
}
catch
{
System.Windows.MessageBox.Show("Error!");
}
finally
{
buttonOpen.IsEnabled = true;
}
}
private void CleanFolder(string path, IProgress<string> progress)
{
var filePaths = Directory.EnumerateFiles(path, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var filePath in filePaths)
{
var matchResult = Regex.Match(filePath, matchPattern);
if (matchResult.Success)
{
File.Delete(filePath);
progress.Report(filePath);
}
}
}
}
}
命名空间文件夹清理器
{
公共部分类主窗口:窗口
{
字符串折叠路径;
字符串匹配模式;
私有无效按钮打开单击(对象发送者,路由目标)
{
FolderBrowserDialog fbd=新建FolderBrowserDialog(){Description=“选择文件夹”};
if(fbd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
{
folderPath=fbd.SelectedPath;
Text=folderPath;
buttonClean.IsEnabled=true;
textBoxList.Text=“文件夹路径:”+folderPath+“\n”;
}
}
专用异步无效按钮清除单击(对象发送方,路由目标)
{
matchPattern=textBoxPattern.Text;
buttonOpen.IsEnabled=false;
buttonClean.IsEnabled=false;
进度=新进度(消息=>
{
textBoxList.AppendText(“文件已删除:“+msg+”\n”);
textBoxList.CaretIndex=textBoxList.Text.Length;
textBoxList.ScrollToEnd();
});
尝试
{
等待任务。运行(()=>CleanFolder(folderPath,progress));
textBoxList.AppendText(“任务完成!”);
textBoxList.CaretIndex=textBoxList.Text.Length;
textBoxList.ScrollToEnd();
}
抓住
{
System.Windows.MessageBox.Show(“错误!”);
}
最后
{
buttonOpen.IsEnabled=true;
}
}
专用文件夹(字符串路径,IProgress进度)
{
var filepath=Directory.EnumerateFiles(路径“***”,System.IO.SearchOption.AllDirectories);
foreach(filePath中的var filePath)
{
var matchResult=Regex.Match(文件路径,匹配模式);
if(matchResult.Success)
{
File.Delete(文件路径);
进度报告(文件路径);
}
}
}
}
}
无法从其他线程控制GUI
但我认为,真正的问题是将字符串和输出连接到文本框是一种非常低效的操作
在您的情况下,最好在单行中显示删除进度或使用进度条
这是我对你问题的解决方案(我改变了两种方法):
我希望这会有所帮助。GUI无法从其他线程控制 但我认为,真正的问题是将字符串和输出连接到文本框是一种非常低效的操作 在您的情况下,最好在单行中显示删除进度或使用进度条 这是我对你问题的解决方案(我改变了两种方法):
我希望这会有所帮助。谢谢大家。简而言之,多亏了C#6.0这本书 我已经找到了解决方案,并且对async/await有了更好的理解 首先,不建议使用
Dispatcher.Invoke
,因为.NETFramework4.5,基于任务的异步已成为主导模式(使用async/awit)
其次,使用async/await有几个原则:
之后的表达式必须是wait
或Task
反对Task
- 如果对方法使用
修饰符,则该方法不async
t 需要手动返回任务
Task`对象方法。编译将封装 方法作为
- 如果使用类似
的方法,则必须在其中使用async Task Foo()
关键字wait
- 如果没有等待的内容,则删除
修饰符,使用async
returntask.Run(()=>{dosomething})返回
对象代码>。现在,您可以在调用Task
的方法中使用Foo()
wait Foo()
无法操作UI,但Task Foo()
可以async Task Foo()
- 谢谢大家。简而言之,多亏了C#6.0这本书
我已经找到了解决方案,并且对async/await有了更好的理解
首先,不建议使用
Dispatcher.Invoke
,因为.NETFramework4.5,基于任务的异步已成为主导模式(使用async/awit)
其次,使用async/await有几个原则:
之后的表达式必须是wait
或Task
反对Task
- 如果对方法使用
修饰符,则该方法不async
t 需要手动返回任务
Task`对象方法。编译将封装 方法作为
- 如果使用类似
的方法,则必须在其中使用async Task Foo()
关键字wait
- 如果没有等待的内容,则删除
修饰符,使用async
returntask.Run(()=>{dosomething})返回
对象代码>。现在,您可以在调用Task
的方法中使用Foo()
wait Foo()
无法操作UI,但Task Foo()
可以async Task Foo()
private async void ButtonClean_Click(object sender, RoutedEventArgs e)
{
matchPattern = textBoxPattern.Text;
buttonOpen.IsEnabled = false;
buttonClean.IsEnabled = false;
await Task.Run(() => CleanFolder(folderPath));
textBoxList.Text += "Mission complete!";
buttonOpen.IsEnabled = true;
}
private void CleanFolder(string path)
{
var filePaths = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories);
foreach (var filePath in filePaths)
{
var matchResult = Regex.Match(filePath, matchPattern);
if (matchResult.Success)
{
File.Delete(filePath);
System.Windows.Application.Current.Dispatcher.Invoke(delegate
{
// this working fast
textBoxList.Text = "File deleted: " + filePath + "\n";
// this working slow and slower over time
//textBoxList.Text += "File deleted: " + filePath + "\n";
textBoxList.ScrollToEnd();
});
}
}
}