簡體   English   中英

MVVMLight WPF ProgressBar 在異步任務中綁定

[英]MVVMLight WPF ProgressBar binding in asynchronous Task

誰能告訴我為什么我的ProgressBarTask結束之前無法更新?

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM