在主线程 UI 中通知 System.Timer

Notify System.Timer in main UI thread

有没有办法通知主 GUI 线程 System.TimerElapsed 方法结束?

我的真实情况是这样的: 我在业务逻辑中有一个 class,它使用 System.Timer 来执行例行操作,因为计时器使用池线程 我不能使用我在 GUI 中使用的事件,因为这些事件将在不同的 GUI 线程。 我需要的是某种通知,通知我的 GUI 线程 Elapsed 方法已完成,然后我可以更新 GUI 字段。 可能吗?

我想到的一个解决方案是使用 System.Windows.Forms.Timer,在它的 Tick 方法中,我在异步等待中执行所有操作,但我不太喜欢它,因为我想在没有业务逻辑工作的情况下离开 GUI,我想了解是否有其他可能的方法来解决我的这种情况。

您可以考虑使用 IProgress<T> abstraction. The business layer class would accept a IProgress<T> implementation that would be provided by the UI layer. Any time a notification will need to be passed to the UI layer, the business layer will invoke the Report method. There is already a built-in implementation of this interface, the Progress<T> class 从业务层通知 UI 层,它会自动将通知编组到 UI 线程,前提是class 在 UI 线程上实例化。示例:

class BusinessLayer
{
    public void Initialize (IProgress<string> progress) { /* ... */ }
}
public Form1()
{
    InitializeComponent();
    var progress = new Progress<string>(message =>
    {
        TextBox1.AppendText($"{message}\r\n");
    });
    BusinessLayer.Initialize(progress);
}

您可以根据需要自由选择IProgress<T>类型T。它可以是像 string 这样简单的东西,也可以是像 (int, string, bool) 这样复杂的 ValueTuple 或自定义类型等

需要注意的是通知的频率。如果业务层 Report 过于频繁,UI 线程可能会阻塞并变得无响应。

非常感谢大家的回答。

我听从了@Teodoro 的建议,这正是我要找的,为了我的需要,我设置了 IProgress<T> 这样的:

public class IA_Routine
{
    IA_Core Core;
    Timer TimeRoutine;
    IProgress<object> ProgressEnd;

    public event EventHandler NotifyEndElapsedRoutine;

    public IA_Routine(IA_Core core)
    {
        Core = core;
        ProgressEnd = new Progress<object>(obj =>
        {
            FuncNotifyElapsedEnd();
        });

        TimeRoutine = new Timer();
        TimeRoutine.AutoReset = true;
        TimeRoutine.Interval = Core.TimingRoutine;
        TimeRoutine.Elapsed += TimeRoutine_Elapsed;
    }

    internal void StartRoutine()
    {
        TimeRoutine.Start();
    }

    private void TimeRoutine_Elapsed(object sender, ElapsedEventArgs e)
    {
        //-- routine functions
        //--
        //--

        ProgressEnd.Report(null);
    }

    void FuncNotifyElapsedEnd()
    {
        NotifyEndElapsedRoutine?.Invoke(this, EventArgs.Empty);
    }
}

我指定Timer是一个System.Timers而class实例是在UI线程中创建的,不知道是不是最好的IProgres<T> 的使用方法,但同时它按我的意愿工作,再次感谢