Создание окна из нового потока в приложении WPF без главного окна

Я работаю над приложением WPF, у которого нет главного окна (оно запускается в области уведомлений с использованием кода из http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx).

В App.xaml.cs я создал новый поток, который запускает некоторый код мониторинга, возвращающий пользовательскую коллекцию предупреждений. В коллекции есть метод render(), который я планировал использовать для отображения окна с информацией о предупреждениях, но я не могу понять, как это сделать. Буду признателен за любой вклад.

Примеры кода ниже:

Приложение.xaml:

<Application x:Class="DowntimeReportMonitor.Views.Icon.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Startup="Application_Startup"
         Exit="Application_Exit">
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="IconDictionary.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>
</Application>

App.xaml.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading;
using System.Windows;

using Hardcodet.Wpf.TaskbarNotification;

using DowntimeReportMonitor.Core;

namespace DowntimeReportMonitor.Views.Icon
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    private TaskbarIcon _taskbaricon;

    private AlertWorker _alertWorker;
    private Thread _alertWorkerThread;

    /// <summary>
    /// Event handler for Application startup
    /// </summary>
    /// <param name="sender">The event sender</param>
    /// <param name="e">Event arguments</param>
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // Create and start a new TaskbarIcon.
        this._taskbaricon = (TaskbarIcon)FindResource("notificationIcon");

        // Create and start a new AlertWorker.
        this._alertWorker = new AlertWorker();
        this._alertWorkerThread = new Thread(this._alertWorker.doWork);
        this._alertWorkerThread.SetApartmentState(ApartmentState.STA);
        this._alertWorkerThread.Start();
    }



    /// <summary>
    /// Event handler for Application exit
    /// </summary>
    /// <param name="sender">The event sender</param>
    /// <param name="e">Event arguments</param>
    private void Application_Exit(object sender, ExitEventArgs e)
    {
        // Stop the alert worker.
        this._alertWorker.requestStop();
        this._alertWorkerThread.Join();

        // Dispose of the notification icon.
        this._taskbaricon.Dispose();
    }
}
}

AlertWorker.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using DowntimeReportMonitor.Core;

namespace DowntimeReportMonitor.Views.Icon
{
class AlertWorker
{
    private volatile bool _stopRequested;

    private ReportMonitor _reportMonitor;

    public AlertWorker()
    {
        _reportMonitor = new ReportMonitor(new wpfRenderableReportAlertCollection());
    }

    public void doWork()
    {
        while (!_stopRequested)
        {
            this._reportMonitor.monitorReports().render();

            Thread.Sleep(30000);
        }
    }

    public void requestStop()
    {
        this._stopRequested = true;
    }
}
}

person bshacklett    schedule 11.11.2011    source источник


Ответы (1)


Ну, во-первых, вам нужен выделенный поток пользовательского интерфейса. Обычно это начальный поток приложения, но вы можете взять любой. (Это должен быть поток STA.)

Затем вы запускаете диспетчер в этом потоке (Dispatcher.CurrentDispatcher.Выполнить).

Затем вы можете отправлять команды в этот поток, используя Dispatcher.Invoke или Dispatcher.BeginInvoke.

Наконец, вы можете опубликовать сообщение в своей теме window.Show для своего пользовательского класса Window.

person Vlad    schedule 11.11.2011
comment
Я последовал твоему совету и, кажется, у меня получилось. Не хватало одной вещи: мне нужно было передать ссылку на диспетчер (this.dispatcher) в фоновый поток. Кроме того... как только новое окно закрывается, оно выходит из всего приложения. Я все еще пытаюсь понять это. - person bshacklett; 17.11.2011
comment
@bshacklett: Что ж, для первой проблемы вы можете сохранить свой диспетчер в статической глобальной переменной, в любом случае это синглтон. Чтобы решить проблему с выходом, вам следует взглянуть на свои настройки: (1) убедитесь, что ваше приложение имеет режим выключения не закрывается главное окно? (2) убедитесь, что ваши рабочие потоки не являются фоновыми потоками (фоновые потоки не поддерживают работу приложения). - person Vlad; 18.11.2011