Minimize to tray icon in WPF

I had to do a bit of searching so, here’s how to minimize your WPF app to a tray icon.  Assume your window is called Window1 for the code below.  Trap Closing, StateChanged and IsVisibleChanged (see xaml). 

xaml:

<window x:Class="MyApp.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="WCFAppVisualHost" Height="383" Width="680" Closing="OnClose" StateChanged="OnStateChanged" IsVisibleChanged="OnIsVisibleChanged"
  >

Associated cs:

private System.Windows.Forms.NotifyIcon m_notifyIcon;

public Window1()
{
    // initialise code here
    m_notifyIcon = new System.Windows.Forms.NotifyIcon();
    m_notifyIcon.BalloonTipText = "The app has been minimised. Click the tray icon to show.";
    m_notifyIcon.BalloonTipTitle = "The App";
    m_notifyIcon.Text = "The App";
    m_notifyIcon.Icon = new System.Drawing.Icon("TheAppIcon.ico");
    m_notifyIcon.Click += new EventHandler(m_notifyIcon_Click);
}

void OnClose(object sender, CancelEventArgs args)
{
    m_notifyIcon.Dispose();
    m_notifyIcon = null;
}

private WindowState m_storedWindowState = WindowState.Normal;
void OnStateChanged(object sender, EventArgs args)
{
    if (WindowState == WindowState.Minimized)
    {
        Hide();
        if(m_notifyIcon != null)
            m_notifyIcon.ShowBalloonTip(2000);
    }
    else
        m_storedWindowState = WindowState;
}
void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
{
    CheckTrayIcon();
}

void m_notifyIcon_Click(object sender, EventArgs e)
{
    Show();
    WindowState = m_storedWindowState;
}
void CheckTrayIcon()
{
    ShowTrayIcon(!IsVisible);
}

void ShowTrayIcon(bool show)
{
    if (m_notifyIcon != null)
        m_notifyIcon.Visible = show;
}

Advertisements

34 thoughts on “Minimize to tray icon in WPF

  1. You need to create *.ico file with your icon. And then you need to replace “TheAppIcon.ico” in this line:

    m_notifyIcon.Icon = new System.Drawing.Icon(”TheAppIcon.ico”);

    with file that you created. This example works fine on my computer.

    Cheers

  2. Thank You, it works

    I simplyfied one method, however:

    void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args) {
    if (m_notifyIcon != null)
    m_notifyIcon.Visible = !IsVisible;
    }

  3. Hi there

    Thanks for above but I am trying to out this. My system is minimised and icon on the taskbar tray. Now how to I get the tooltip when I do mouseover the minimised icon on taskbar?

    regards

  4. Hi,
    I was trying to get this working but I am getting this error:

    Exception has been thrown by the target of an invocation. Error in markup file ‘Window1.xaml’

    I added the dll’s and all seem ok. Any suggestions?

    Nick

  5. I commented out this line and the program starts.

    //m_notifyIcon.Icon = new System.Drawing.Icon(“original_logo1.ico”);

    When I minimize the window, there is no icon in system tray. Obviously, i did not set the icon.

    How can I make it so that will work?

  6. I got it sorted.

    m_notifyIcon.Icon = new System.Drawing.Icon(@”c:\icon.ico”);

    I used another icon from the c drive so i guess there was
    some problem with the location of the icon.

    Thanks for the code. I learned this one today. 😉

  7. Hi,
    Thanks for the solution but i am getting run time error .
    I am getting following error :-

    System.Windows.Markup.XamlParseException was unhandled
    Message=”Cannot create instance of ‘Window1’ defined in assembly ‘WpfApplication1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’. Exception has been thrown by the target of an invocation. Error in markup file ‘Window1.xaml’ Line 2 Position 2.”
    Source=”PresentationFramework”
    LineNumber=2
    LinePosition=2
    StackTrace:
    at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType)
    at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException)
    at System.Windows.Markup.BamlRecordReader.ThrowExceptionWithLine(String message, Exception innerException)
    at System.Windows.Markup.BamlRecordReader.CreateInstanceFromType(Type type, Int16 typeId, Boolean throwOnFail)
    at System.Windows.Markup.BamlRecordReader.GetElementAndFlags(BamlElementStartRecord bamlElementStartRecord, Object& element, ReaderFlags& flags, Type& delayCreatedType, Int16& delayCreatedTypeId)
    at System.Windows.Markup.BamlRecordReader.BaseReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
    at System.Windows.Markup.BamlRecordReader.ReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
    at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
    at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord)
    at System.Windows.Markup.TreeBuilderBamlTranslator.ParseFragment()
    at System.Windows.Markup.TreeBuilder.Parse()
    at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
    at System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
    at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties)
    at System.Windows.Application.DoStartup()
    at System.Windows.Application.b__0(Object unused)
    at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
    at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
    at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
    at System.Windows.Threading.DispatcherOperation.InvokeImpl()
    at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
    at System.Threading.ExecutionContext.runTryCode(Object userData)
    at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Windows.Threading.DispatcherOperation.Invoke()
    at System.Windows.Threading.Dispatcher.ProcessQueue()
    at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
    at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
    at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
    at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
    at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
    at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
    at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
    at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
    at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
    at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
    at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
    at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
    at System.Windows.Threading.Dispatcher.Run()
    at System.Windows.Application.RunDispatcher(Object ignore)
    at System.Windows.Application.RunInternal(Window window)
    at System.Windows.Application.Run(Window window)
    at System.Windows.Application.Run()
    at WpfApplication1.App.Main() in C:\Documents and Settings\v-robhop\My Documents\Expression\Expression Blend Projects\WpfApplication1\WpfApplication1\obj\Debug\App.g.cs:line 0
    at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    InnerException: System.Reflection.TargetInvocationException
    Message=”Exception has been thrown by the target of an invocation.”
    Source=”mscorlib”
    StackTrace:
    at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck)
    at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache)
    at System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache)
    at System.Activator.CreateInstance(Type type, Boolean nonPublic)
    at System.Windows.Markup.BamlRecordReader.CreateInstanceFromType(Type type, Int16 typeId, Boolean throwOnFail)
    InnerException: System.IO.FileNotFoundException
    Message=”Could not find file ‘C:\\Documents and Settings\\v-robhop\\My Documents\\Expression\\Expression Blend Projects\\WpfApplication1\\WpfApplication1\\bin\\Debug\\Windows_icon.ico’.”
    Source=”mscorlib”
    FileName=”C:\\Documents and Settings\\v-robhop\\My Documents\\Expression\\Expression Blend Projects\\WpfApplication1\\WpfApplication1\\bin\\Debug\\Windows_icon.ico”
    StackTrace:
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
    at System.Drawing.Icon..ctor(String fileName, Int32 width, Int32 height)
    at System.Drawing.Icon..ctor(String fileName)
    at WpfApplication1.Window1..ctor() in C:\Documents and Settings\v-robhop\My Documents\Expression\Expression Blend Projects\WpfApplication1\WpfApplication1\Window1.xaml.cs:line 32
    InnerException:

    Can anybody help me on this?( I am totally new to wpf and its coding 🙂 )

    • I have the same error:


      No se controló System.Windows.Markup.XamlParseException
      Message="No se puede crear una instancia de 'Window1' en el ensamblado 'Proyecto01, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Se produjo una excepción en el destino de la invocación. Error en el archivo de marcado 'Window1.xaml' Línea 1 Posición 9."
      Source="PresentationFramework"
      LineNumber=1
      LinePosition=9
      (....)

      How can you fixed…?

  8. Also your Icon should be added as an “Embedded Resouce” not “Resouce”. (see properties in Visual Studio)
    “Resource” is for WPF and “Embedded Resouce” is for backward compatibility with winforms. Because this component was designed for winforms it expects a winforms compatible resource.

  9. Pingback: kevin Mocha - Create System Tray Applications in WPF

  10. “Too bad this requires loading the WinForms assembly.”… T

    True, but you do what you’ve got to do under time constraints. There are so many things you can do under WinForms that you can’t under Wpf without a TON of hassle that I find it hard to want to use Wpf. I’ve used it a few times, but for business apps it just doesn’t make sense for me yet.

  11. Hi there,

    Thanks for the info, very helpful! We tried the same stuff, it works fine in the vs2008 or in the bin folder, but when we publish it as a stand alone application, it comes out with error when i minimize, when we debug, it shows the error, that it is not able to find the favicon.ico in some strange path. It means during publish, the project is not taking the icon file, is there any solution for the same!

    Thanks in advance!

  12. Thanks You, i have an problem in cs code !
    Could you help me to solve this !
    —————————–
    void OnClose(object sender, CancelEventArgs Args)
    {
    m_notifyIcon.Dispose();
    m_notifyIcon = null;
    }
    —————————–
    Error 1 The type or namespace name ‘CancelEventArgs’ could not be found (are you missing a using directive or an assembly reference?)

    thanks,

  13. Pingback: Alguns links para WPF « Prof. Daniel Barbosa

  14. Thanks , it is very helpfull for me

    If we want to add Context menu item in this code what kind of changes have to be done in code… solve the problem

  15. Also for the icon issue:

    m_notifyIcon.Icon = new Icon(AppDomain.CurrentDomain.BaseDirectory + “Small.ico”);

    this needs an icon file in the bin folder called small.ico, size 16×16

  16. It worked fine for me after i followed Artur Carvalho sugestion and put the icon as embeded resource.

    Thanks for the great article.

    Paulo

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s