我想要什么
每当windows的时区改变时,我都想做点什么。
到目前为止我所拥有的
为此,我实现了事件SystemEvents.TimeChanged,如下所示:
在构造函数中:

SystemEvents.TimeChanged += SystemEvents_TimeChanged;

活动主体:
void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        MessageBox.Show("Test1");}

有什么问题
在Windows中更改时间或时区时,不会触发事件。
我试过的
当我在一个干净的winforms应用程序中编写上述代码时,一切都按预期工作。但在我的应用程序中没有,这是因为它包含了很多其他代码。
我看不出我还有其他的事件,这些事件会阻止上述事件的发生。
我的问题是
有没有人知道是什么原因导致上面的代码没有在我的应用程序中触发,而是在我创建一个只包含上面代码的新项目/应用程序时按预期工作?
更新1
发生这种情况是因为我在调用
Application.Run(new FormMain());

然后,systemevents会粘在启动屏幕创建的线程上,即使该线程在应用程序加载后也会终止。
现在的问题是,当应用程序加载后,是否有方法告诉SystemEvents现在应该使用“正确的”UI线程?

最佳答案

这个关于问题更新1部分的答案,因此在原始问题中提供的代码示例是有效的。
我花了一些时间来解决这个问题。因此,我没有对您的代码的完整概述我为这个解决方案即兴制作了两个winforms(一个作为splash,另一个作为main),当然这只是一个示例来说明这个概念。
据我所知,当你启动你的软件时,它从splash部分开始作为单独的线程,当splash完成后,比formmain启动之后。你可以做得更好,使用ApplicationContext。您可以创建自己的上下文类,该类是从ApplicationContext扩展而来的,在该类中,您可以使用各自的逻辑声明splash和formmain。现在在您的情况下,您需要确保formmain在splash之后的某个时间点启动,或者类似的事情(我不知道您的软件是如何工作/流动的)。
在context类中,您可以创建订阅和取消订阅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);
    }
}

现在在我们的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;
}

它的工作原理如下:
c# - SystemEvents.TimeChanged未触发(已更新!)-LMLPHP
文档
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.run?view=netframework-4.8
https://docs.microsoft.com/en-us/dotnet/api/microsoft.win32.systemevents?view=netframework-4.8

关于c# - SystemEvents.TimeChanged未触发(已更新!),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57665982/

10-10 11:43