[英]MVVMLight WPF ProgressBar binding in asynchronous Task
誰能告訴我為什么我的ProgressBar
在Task
結束之前無法更新?
ProgressBar
值綁定到我的 ViewModel 屬性,稱為ProgressCurrentValue ; 並且例程在Task
中。 我還嘗試使用 MVVMLight 的DispatcherHelper.CheckBeginInvokeOnUI()
function 更新 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 的回調中調用的,而 MVVMLight IMessenger
本身是從 Button RelayCommand
發送的。 結果,似乎一切都保留在 UIThread 上。
也許這對大多數人來說是顯而易見的,但我沒有發現它。 答案是明確地在后台線程上調用Task
。 所以而不是:
await ProcessCSVFiles(...);
我不得不打電話:
await Task.Run(() => ProcessCSVFiles(...);
不確定我的診斷是否正確,所以我很樂意任何人糾正我,但上面的解決方案似乎有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.