[MVVMLight WPF ProgressBar异步任务中的绑定

问题描述 投票:0回答:1

谁能告诉我为什么我的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.
    }
c# wpf async-await task mvvm-light
1个回答
0
投票

阿,我真是个脾气暴躁的人。

陷阱是Task是从MVVMLight IMessenger的回调中调用的,该回调本身是从Button RelayCommand发送的。结果,似乎所有内容都保留在UIThread上。

也许这对大多数人来说都是显而易见的,但是我没有发现它。答案是明确地在后台线程上调用Task。因此,代替:

await ProcessCSVFiles(...);

我不得不打电话:

await Task.Run(() => ProcessCSVFiles(...);

不确定我的诊断是否正确,所以我很乐意任何人都可以纠正我,但上述解决方案似乎有效。

© www.soinside.com 2019 - 2024. All rights reserved.