1

I'm working on a WPF application that has no main window (it runs in the notification area using code from http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx).

In the App.xaml.cs, I've created a new thread which runs some monitoring code that returns a custom collection of alerts. The collection has a render() method which I planned to use to show a window with the alert information in them, but I can't figure out how to accomplish it. I'd be grateful for any input.

Code samples below:

App.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;
    }
}
}
bshacklett
  • 1,802
  • 5
  • 23
  • 45

1 Answers1

2

Well, first of all, you need a dedicated UI thread. Usually it's the initial application thread, but you can take any. (It must be an STA thread.)

Next, you start a dispather in that thread (Dispatcher.CurrentDispatcher.Run).

Next, you can post commands to that thread using Dispatcher.Invoke or Dispatcher.BeginInvoke.

Finally, you can post to your thread window.Show for your custom Window class.

Vlad
  • 35,022
  • 6
  • 77
  • 199
  • I followed your advice and it seems to have done the trick. One thing that was missing is that I had to pass a reference to the dispatcher (this.dispatcher) to the background thread. Also... once the new window is closed, it exits the entire application. I'm still trying to figure that one out. – bshacklett Nov 17 '11 at 15:14
  • @bshacklett: Well, for the first problem you could save your dispatcher in a static global variable, it's a singleton anyway. For the problem of exiting, you should look at your settings: (1) check that your application has [shutdown mode](http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx) not "on main window close"? (2) check that your worker threads are not background threads (the background threads don't keep the application alive). – Vlad Nov 18 '11 at 14:20