谁能告诉我为什么我的ProgressBar
直到Task
结束都无法更新?
ProgressBar
值绑定到我的ViewModel属性,称为ProgressCurrentValue;并且例程位于Task
之内。我还尝试使用MVVMLight的DispatcherHelper.CheckBeginInvokeOnUI()
函数更新UI线程上的ProgressCurrentValue,但仍然没有成功。我确定我缺少明显的东西;有人可以看到吗?
视图
<UserControl x:Class="xxxxxx.Views.ProcessingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:xxxxxx.Views"
mc:Ignorable="d"
DataContext="{Binding ProcessingVM, Source={StaticResource Locator}}"
x:Name="RunningControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ProgressBar Grid.Row="0" Maximum="{Binding ProgressMaximum}" Minimum="{Binding ProgressMinimum}" Value="{Binding ProgressCurrentValue}" Height="20" />
<!-- etc. -->
</Grid>
</UserControl>
ViewModel(相关部分)
private int _progressMinimum;
/// <summary>
/// Gets or sets the minimum of the progress control.
/// </summary>
public int ProgressMinimum
{
get { return _progressMinimum; }
set { Set(ref _progressMinimum, value); }
}
private int _progressMaximum;
/// <summary>
/// Gets or sets the maximum of the progress control.
/// </summary>
public int ProgressMaximum
{
get { return _progressMaximum; }
set { Set(ref _progressMaximum, value); }
}
private int _progressCurrentValue;
/// <summary>
/// Gets or sets the current value of the progress control.
/// </summary>
public int ProgressCurrentValue
{
get { return _progressCurrentValue; }
set { Set(ref _progressCurrentValue, value); }
}
private async Task ProcessCSVFiles(string[] fullpaths)
{
// Get the current settings for use in the data processing.
ObjectStringPair setting = await _service.FirstSettingAsync();
if (!(setting.Item is Setting s))
{
await SendFlashMessageAsync(new FlashMessage("Unable to locate settings.", AlertLevels.Danger));
return;
}
// Set the progress parameters.
ProgressProcessText = "Processing " + ((fullpaths.Length == 1) ? Path.GetFileName(fullpaths[0]) : "multiple files") + " ...";
ProgressMinimum = 0;
ProgressMaximum = 100;
ProgressCurrentValue = 0;
// Convert the CSV files to DataTables.
List<DataTable> tables = new List<DataTable>();
int i = 0;
int rowCount = 0;
foreach(string fullname in fullpaths)
{
ObjectStringPair reader = await _service.GetDataTableWithCSVHeadersAsync(fullname, headers);
if (reader.Item is DataTable dt)
{
tables.Add(dt);
rowCount += dt.Rows.Count;
}
i++;
}
// Abandon if there are no datatables.
if (tables.Count == 0) { return; }
double progressIncrement = rowCount / 100;
rowCount = 0;
foreach (DataTable table in tables)
{
foreach (DataRow row in table.Rows)
{
// Update the progress control.
rowCount++;
if ((int)(rowCount / progressIncrement) > ProgressCurrentValue)
{
ProgressCurrentValue = (int)(rowCount / progressIncrement);
}
// Processing code.
}
}
// Close the progress control.
}
阿,我真是个脾气暴躁的人。
陷阱是Task
是从MVVMLight IMessenger
的回调中调用的,该回调本身是从Button RelayCommand
发送的。结果,似乎所有内容都保留在UIThread上。
也许这对大多数人来说都是显而易见的,但是我没有发现它。答案是明确地在后台线程上调用Task
。因此,代替:
await ProcessCSVFiles(...);
我不得不打电话:
await Task.Run(() => ProcessCSVFiles(...);
不确定我的诊断是否正确,所以我很乐意任何人都可以纠正我,但上述解决方案似乎有效。