等待任务完成而不阻塞 UI,奇怪的异常
Wait for task to finish without blocking the UI, strange exception
我创建了一个小应用程序来使用基本的 mvvm 模式重命名一些文件。
文件被复制到具有新名称的新文件夹,并且有一个进度条显示进度(成功)。由于有很多文件,我通过 Task.Factory.StartNew(...) 进行处理。进度条颜色为橙色;当所有文件都重命名后,颜色应变为绿色。
这是 xaml 的一部分:
<ProgressBar x:Name="pBar" HorizontalAlignment="Left" Height="20" Margin="10,5" Foreground="{Binding ProgBarBrush}" VerticalAlignment="Top" Width="100" Value="{Binding ProgBarValue}" Maximum="{Binding MaxIndex}"/>
视图模型:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
private int _maxIndex;
public int MaxIndex
{
get { return _maxIndex; }
set
{
if (value == _maxIndex)
return;
_maxIndex = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaxIndex)));
}
}
private int _pBarValue;
public int ProgBarValue
{
get { return _pBarValue; }
set
{
if (value == _pBarValue)
return;
_pBarValue = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ProgBarValue)));
}
}
private SolidColorBrush _brush;
public SolidColorBrush ProgBarBrush
{
get { return _brush; }
set
{
if (value == _brush)
return;
_brush = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ProgBarBrush)));
}
}
}
任务:
private void StartRename_Click(object sender, RoutedEventArgs e)
{
var newDir = dir + @"\Renamed";
Directory.CreateDirectory(newDir);
vm.ProgBarValue = 0;
vm.ProgBarBrush = new SolidColorBrush(Colors.Orange);
Task t1 = Task.Factory.StartNew(() =>
{
foreach (var pic in pics)
{
if (File.Exists(newDir + @"\" + pic.newName))
{
MessageBox.Show("File " + newDir + @"\" + pic.newName + " already exists. Skipping remaining files...", "File already exists");
return;
}
File.Copy(pic.fileInfo.FullName, newDir + @"\" + pic.newName);
vm.ProgBarValue++;
}
vm.ProgBarBrush = new SolidColorBrush(Colors.Green);
});
}
绑定有效 - 进度条的值发生变化,UI 线程中的第一个颜色也变为橙色。这些文件也以我想要的方式被复制和重命名。
但是当我像这样改变颜色时,我得到一个奇怪的 "kind of exception"(Visual Studio 2017 只是停止):
Ihre App wurde angehalten, aber es gibt keinen anzuzeigenden Code,
da alle Threads externen Code ausgeführt haben (normalerweise System-
oder Frameworkcode).
Your app was halted, but there is no code to be shown because all
threads ran external code (usually System or Framworkcode) => this is my own translation
当我使用 ContinueWith 时,我得到相同的 "exception"。使用 Task.WaitAll() 然后在 UI 线程中进行颜色设置会冻结 UI。如何在不冻结 UI 的情况下重命名所有文件后更改颜色?
感谢您的帮助。
您需要从 UI 线程更改进度条颜色和值。您可以使用 async/await
轻松做到这一点,如本示例所示。另外,我使用 IProgress
.
更新了进度
private async void StartRename_Click(object sender, RoutedEventArgs e)
{
var newDir = dir + @"\Renamed";
Directory.CreateDirectory(newDir);
vm.ProgBarValue = 0;
vm.ProgBarBrush = new SolidColorBrush(Colors.Orange);
var progress = new Progress<int>(_ => vm.ProgBarValue++)
await Task.Run(() =>
{
foreach (var pic in pics)
{
if (File.Exists(newDir + @"\" + pic.newName))
{
MessageBox.Show("File " + newDir + @"\" + pic.newName + " already exists. Skipping remaining files...", "File already exists");
return;
}
File.Copy(pic.fileInfo.FullName, newDir + @"\" + pic.newName);
progress.Report(1);
}
});
vm.ProgBarBrush = new SolidColorBrush(Colors.Green);
}
正如@ckuri 在评论中提到的,IO 绑定操作可以通过 async
api 正确完成。 See this reference 关于如何进一步改进代码。给出的第一个示例是异步复制文件。
我创建了一个小应用程序来使用基本的 mvvm 模式重命名一些文件。 文件被复制到具有新名称的新文件夹,并且有一个进度条显示进度(成功)。由于有很多文件,我通过 Task.Factory.StartNew(...) 进行处理。进度条颜色为橙色;当所有文件都重命名后,颜色应变为绿色。
这是 xaml 的一部分:
<ProgressBar x:Name="pBar" HorizontalAlignment="Left" Height="20" Margin="10,5" Foreground="{Binding ProgBarBrush}" VerticalAlignment="Top" Width="100" Value="{Binding ProgBarValue}" Maximum="{Binding MaxIndex}"/>
视图模型:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
private int _maxIndex;
public int MaxIndex
{
get { return _maxIndex; }
set
{
if (value == _maxIndex)
return;
_maxIndex = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaxIndex)));
}
}
private int _pBarValue;
public int ProgBarValue
{
get { return _pBarValue; }
set
{
if (value == _pBarValue)
return;
_pBarValue = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ProgBarValue)));
}
}
private SolidColorBrush _brush;
public SolidColorBrush ProgBarBrush
{
get { return _brush; }
set
{
if (value == _brush)
return;
_brush = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ProgBarBrush)));
}
}
}
任务:
private void StartRename_Click(object sender, RoutedEventArgs e)
{
var newDir = dir + @"\Renamed";
Directory.CreateDirectory(newDir);
vm.ProgBarValue = 0;
vm.ProgBarBrush = new SolidColorBrush(Colors.Orange);
Task t1 = Task.Factory.StartNew(() =>
{
foreach (var pic in pics)
{
if (File.Exists(newDir + @"\" + pic.newName))
{
MessageBox.Show("File " + newDir + @"\" + pic.newName + " already exists. Skipping remaining files...", "File already exists");
return;
}
File.Copy(pic.fileInfo.FullName, newDir + @"\" + pic.newName);
vm.ProgBarValue++;
}
vm.ProgBarBrush = new SolidColorBrush(Colors.Green);
});
}
绑定有效 - 进度条的值发生变化,UI 线程中的第一个颜色也变为橙色。这些文件也以我想要的方式被复制和重命名。 但是当我像这样改变颜色时,我得到一个奇怪的 "kind of exception"(Visual Studio 2017 只是停止):
Ihre App wurde angehalten, aber es gibt keinen anzuzeigenden Code, da alle Threads externen Code ausgeführt haben (normalerweise System- oder Frameworkcode).
Your app was halted, but there is no code to be shown because all threads ran external code (usually System or Framworkcode) => this is my own translation
当我使用 ContinueWith 时,我得到相同的 "exception"。使用 Task.WaitAll() 然后在 UI 线程中进行颜色设置会冻结 UI。如何在不冻结 UI 的情况下重命名所有文件后更改颜色?
感谢您的帮助。
您需要从 UI 线程更改进度条颜色和值。您可以使用 async/await
轻松做到这一点,如本示例所示。另外,我使用 IProgress
.
private async void StartRename_Click(object sender, RoutedEventArgs e)
{
var newDir = dir + @"\Renamed";
Directory.CreateDirectory(newDir);
vm.ProgBarValue = 0;
vm.ProgBarBrush = new SolidColorBrush(Colors.Orange);
var progress = new Progress<int>(_ => vm.ProgBarValue++)
await Task.Run(() =>
{
foreach (var pic in pics)
{
if (File.Exists(newDir + @"\" + pic.newName))
{
MessageBox.Show("File " + newDir + @"\" + pic.newName + " already exists. Skipping remaining files...", "File already exists");
return;
}
File.Copy(pic.fileInfo.FullName, newDir + @"\" + pic.newName);
progress.Report(1);
}
});
vm.ProgBarBrush = new SolidColorBrush(Colors.Green);
}
正如@ckuri 在评论中提到的,IO 绑定操作可以通过 async
api 正确完成。 See this reference 关于如何进一步改进代码。给出的第一个示例是异步复制文件。