在 .NET 核心中的功能同步期间更新 TextBlock

问题描述

我正在使用 .NET Core 制作一个小程序,但我不知道如何实现:我想在可能需要很长时间的功能期间更新我的 GUI 中的文本块。它不是异步的,我只有一个线程。我的 XAML 是:

fn f(x: Box<dyn MyTrait>) { ... }

在 UI 中有一个调用函数的按钮,在此函数中,我想向用户显示一些信息,例如“步骤 1 已完成”、“步骤 2 正在进行中”等;我不想也不需要详细的更新,只是提供一些关于正在发生的事情的想法。 XAML.CS 是:

<mah:MetroWindow x:Class="MyProgram.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProgram"
        xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
        WindowStartupLocation="CenterScreen"
        mc:Ignorable="d"
        Title="My Title" Height="550" Width="850" FontSize="14" FontFamily="Dosis,Verdana,Comic Sans MS" >

    <Grid>
        <!-- Grid Rows and Column DeFinitions -->
        
        <!-- Fields in the UI -->

        <TextBlock Grid.Row="5" Name="lblStatusTxtBlk" Grid.Column="1"  Grid.ColumnSpan="3" Height="auto" textwrapping="Wrap" Margin="10 30" Text="{Binding lblStatus,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

    </Grid>
</mah:MetroWindow>

当我启动程序时,我在文本块中读到“start”,所以我可以说绑定有效。但是,当函数运行时,TextBlock 直到最后才会更新,而不是每一步都更新。我在编译时和运行时都没有收到任何错误或警告。怎么解决

解决方法

您可能应该为长时间运行的任务使用不同的线程(这是它的目的)!我希望如果你这样做,更新会在你期望的时候出现,你的用户界面也应该响应更快。

可以使用实现 Progress<T> 接口的 IProgress<T> 类将进度发送回 UI 线程,两者都可以在 System 中找到。

为了简洁起见,我没有将您的示例修改为工作程序,而是将控制台版本放在一起:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var progReporter = new Progress<int>(o => Report(o));
            await Task.Run(() => LongProcess(progReporter));

            Console.WriteLine("Task Complete");
        }

        private static void Report(int progress)
            => Console.WriteLine($"{progress}% completed");

        private static void LongProcess(IProgress<int> progReporter)
        {
            // Step 1...
            Thread.Sleep(300);
            progReporter.Report(25);
            // Step 2...
            Thread.Sleep(300);
            progReporter.Report(50);
            // Step 3...
            Thread.Sleep(300);
            progReporter.Report(75);
            // Step 4...
            Thread.Sleep(300);
            progReporter.Report(100);
        }
    }
}

唯一需要注意的是,传递给 progReporter 的 lambda 捕获了主线程的上下文——GUI 程序中的 UI 线程是什么——所以在主线程上定义它很重要,并且不在 LongProcress() 内或由 Task.Run() 调用的任何其他地方。显然,您的 lambda 将更新 lblStatus

另请注意,任务有时会在显示上次更新之前完成 - 确保您的 UI 可以干净地应对这种情况。

MSDN 博客上有一篇很好的技术文章:https://devblogs.microsoft.com/dotnet/async-in-4-5-enabling-progress-and-cancellation-in-async-apis/

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...