SystemEvents.TimeChanged未触发(已更新!)

Joh*_*aps 7 c# events winforms

我想要的是

每当Windows中的时区更改时,我都想做些事情。

到目前为止我有什么

为此,我实现了事件SystemEvents.TimeChanged,如下所示:

在构造函数中:

SystemEvents.TimeChanged += SystemEvents_TimeChanged;
Run Code Online (Sandbox Code Playgroud)

事件主体:

void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        MessageBox.Show("Test1");}
Run Code Online (Sandbox Code Playgroud)

问题是什么

在Windows中更改时间或时区时,不会触发该事件。

我尝试过的

当我在干净的WinForms应用程序中编写以上代码时,一切都按预期工作。但是在我的应用程序中却没有,原因是包含许多其他代码。我看不到我还有其他任何事件,应该阻止上述事件的触发。

我的问题是

有谁知道什么可能导致上述代码无法在我的应用程序中触发,但是在创建仅包含上述代码的新项目/应用程序时按预期工作?

更新1

这是因为我在调用之前在单独的线程中显示了启动屏幕

Application.Run(new FormMain());
Run Code Online (Sandbox Code Playgroud)

然后,SystemEvents会坚持启动屏幕创建的线程,即使在加载应用程序后该线程也会终止。

现在的问题是,是否有一种方法可以告诉SystemEvents,当应用程序加载后,现在应该使用“正确的” UI线程吗?

may*_*ʎɐɯ 7

该问题关于问题UPDATE 1部分,因此原始问题中提供的代码示例正在工作。

我花了一些时间解决这个问题。因此,我没有为您的代码提供完整的概述,我为该解决方案即兴使用了2个WinForms(一个作为启动,另一个作为主要),当然,这只是说明概念的示例。

据我了解,当您启动软件时,它以启动部分作为单独的线程开始,并在启动完成后从FormMain开始。使用,您可以做得更好ApplicationContext。您可以创建自己的上下文类,该上下文类从该类扩展而来,ApplicationContext并在该类中使用各自的逻辑声明Splash和FormMain。现在,根据您的情况,您需要确保FormMain在Splash之后的某个时间点启动或类似的操作(我不知道您的软件如何工作/运行)。

在上下文类中,您可以创建要订阅和取消订阅的方法,SystemEvents.TimeChanged以便您可以聆听时间的变化。我出于演示目的还创建了一个BindingList演示时间的更改。

现在让我们显示一些代码:

public static void Main()
{
    // use own created context
    MainApplicationContext context = new MainApplicationContext();
    Application.Run(context);
}

// just quick way to demonstrate how we collect time changes
public static BindingList<string> Logs { get; private set; }

private class MainApplicationContext : ApplicationContext
{
    private int _formCount;

    public MainApplicationContext()
    {
        Logs = new BindingList<string>();

        _formCount = 0;

        // splash screen
        var splash = new FormSplash();
        splash.Closed += OnFormClosed;
        splash.Load += OnFormOpening;
        splash.Closing += OnFormClosing;
        _formCount++;
        splash.Show();

        // For demo, make some logic that close splash when program loaded.
        Thread.Sleep(2000);

        var main = new FormMain();
        main.Closed += OnFormClosed;
        main.Load += OnFormOpening;
        main.Closing += OnFormClosing;
        _formCount++;

        splash.Close();
        main.Show();
    }

    private void OnFormOpening(object sender, EventArgs e)
    {
        SystemEvents.TimeChanged += SystemEvents_TimeChanged;
    }

    private void OnFormClosing(object sender, CancelEventArgs e)
    {
        SystemEvents.TimeChanged -= SystemEvents_TimeChanged;
    }

    private void OnFormClosed(object sender, EventArgs e)
    {
        _formCount--;
        if (_formCount == 0)
        {
            ExitThread();
        }
    }

    private void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        var text = $"TimeChanged, Time changed; it is now {DateTime.Now.ToLongTimeString()}";
        Logs.Add(text);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在在我们的FormMain中,创建名为listbox的框LogListBox

public FormMain()
{
    InitializeComponent();
    Load += ListChanged;
}

// this keep list of time changes events updated if changed this could be log or some thing else.
private void ListChanged(object sender, EventArgs e)
{
    LogListBox.DataSource = Program.Logs;
}
Run Code Online (Sandbox Code Playgroud)

以及它是如何工作的: 在此处输入图片说明

文献资料