WPF NotifyIcon来自后台线程

jpa*_*alm 5 wpf

我知道通常不应该从UI线程以外的线程触摸UI元素,但我是WPF的新手,我想知道我当前的工作实现是否可以改进.

我有一个仅由通知托盘图标组成的应用程序,我想从后台线程更新该图标.

这是我的Program.cs入口点:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        using (IconHandler notify = new IconHandler())
        {
            notify.Display();
            Application.Run();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的IconHandler.cs通知图标处理程序类:

class IconHandler : IDisposable
{

    NotifyIcon ni;

    public IconHandler()
    {
        ni = new NotifyIcon();
    }

    public void Display()
    {
        ni.MouseClick += new MouseEventHandler(ni_MouseClick);
        ni.Icon = Resources.icon1;
        ni.Visible = true;

        new Thread(new ThreadStart(UpdateIcon)).Start();
    }

    public void UpdateIcon()
    {
        while (true)
        {
            // reference ni directly, it updates fine
        }
    }

    public void Dispose()
    {
        ni.Dispose();
    }

    void ni_MouseClick(object sender, MouseEventArgs e)
    {
        // something useful
    }
}
Run Code Online (Sandbox Code Playgroud)

这有什么明显不正确的吗?这对我来说似乎有点可疑 - 这只是我的第一次尝试.它似乎适合我想做的事情,有没有人有任何更好的实施建议?我会在这个设置中遇到生命周期问题吗?

Gle*_*mas 0

while(true)代码中的循环将导致大量 CPU/资源使用。也许将例如添加Thread.Sleep(1000)到循环中以允许更新之间的中断。

后台线程的最佳用法是在后台线程上执行长时间运行的工作(例如与服务器/数据库的通信),并且一旦线程完成,让 UI 线程更新 UI。

使用后台工作者:

var worker = new BackgroundWorker();

worker.DoWork += (sender, args) =>
{
    // long running work
};

worker.RunWorkerCompleted += (sender, args) =>
{
    // Update UI
};

worker.RunWorkerAsync();
Run Code Online (Sandbox Code Playgroud)

异步/等待模式:

public async void DoWork()
{
    // Do long running task
    var data = await Task.Run(() => new object());

    // Update UI here
}
Run Code Online (Sandbox Code Playgroud)

任务工厂:

Task.Factory.StartNew(() => new Object()).ContinueWith(task => MessageBox.Show(task.Result.ToString()), TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)

如果 UI 需要不断循环更新,可以使用计时器定期重新启动该进程。这将使您的 CPU 免受冲击。