読者です 読者をやめる 読者になる 読者になる

SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

WPFでの常駐アプリの作り方

WPF C#

WPFでは、タスクトレイの機能を使うためのAPIは用意されていません。
そのため、FormsのAPIを使って実装する必要があります。

概要

Pro WPF を参考に、タスクトレイ関連の機能をコンポーネントクラスでラップして、WPF側からつかっています。

Pro Wpf in C# 2010

Pro Wpf in C# 2010

↓こんな感じ

手順

  1. WPFのプロジェクトで、新規項目の追加⇒コンポーネントクラスを選ぶ(NotifyIconWrapperという名前で作成)
  2. 作成したコンポーネントクラスのデザイナ画面で、CommonControlsから、NotifyIconを選んでドロップ
    1. このとき、System.Windows.Forms.dllが参照に追加される
    2. System.Drawing.dllの参照を手動で追加する。
  3. ContextMenuStripをドロップする
  4. NotifyIconを選んで、以下のプロパティを編集する
    1. Text・・・タスクトレイのアイコン上にカーソルを置いたときに、ツールチップで表示されるテキスト
    2. Icon・・・タスクトレイに表示されるアイコン
    3. ContextMenuStrip・・・3.で追加したメニュー
  5. コンテキストメニューを作成する
    1. ドロップしたメニュー項目を右クリック⇒項目の編集
    2. 表示されたエディタでメニューを編集
  6. コンポーネントクラスのコードビハインドで、メニュー項目を選択した時のイベントハンドラを追加を追加
  7. 起動時にはウィンドウを表示せず、タスクトレイへの登録を行う
    1. App.xamlのStartupUriを削除
    2. App.xaml.csで、OnStartupのメソッドをオーバーライド
  8. このままだと、ウィンドウの閉じるボタンを押したときにウィンドウが閉じられてしまうので、以下のどちらかの対処をする
    1. Closingイベントで、ウィンドウのクローズをキャンセル&ウィンドウを最小化して、タスクバーからも消す
    2. ウィンドウを閉じるのを許可しておき、再度表示する際に、ウィンドウのインスタンスを再生成する。

(下のコードでは、前者の方法を使ってます)

  1. icoの指定をコードビハインドで行う
    1. デザイナでアイコンの設定をすると、resxファイルでiconの指定が行われる。
    2. なんかイヤなので、コンポーネントクラスのコンストラクタに、アイコンの設定処理を追加

コード

App.xaml
<Application x:Class="NotifyIcon.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>
App.xaml.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace NotifyIcon
{
    /// <summary>
    /// App.xaml の相互作用ロジック
    /// </summary>
    public partial class App : Application
    {
        private NotifyIconWrapper component;

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            this.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
            component = new NotifyIconWrapper();
        }

        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);
            component.Dispose();
        }
    }
}
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace NotifyIcon
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // クローズ処理をキャンセルして、タスクバーの表示も消す
            e.Cancel = true;
            this.WindowState = System.Windows.WindowState.Minimized;
            this.ShowInTaskbar = false;
        }
    }
}
NotifyIconWrapper.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NotifyIcon
{
    public partial class NotifyIconWrapper : Component
    {
        public NotifyIconWrapper()
        {
            InitializeComponent();

            // イベントハンドラの設定
            toolStripMenuItemShow.Click += toolStripMenuItemShow_Click;
            toolStripMenuItemExit.Click += toolStripMenuItemExit_Click;

            // タスクトレイ用のアイコンを設定
            System.IO.Stream iconStream = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/NotifyIcon;component/Icons/Icon1.ico")).Stream;
            this.notifyIcon1.Icon = new System.Drawing.Icon(iconStream);
        }

        // 常駐させるウィンドウはここで保持する
        private MainWindow win = new MainWindow();

        void toolStripMenuItemShow_Click(object sender, EventArgs e)
        {
            ShowWindow();
        }

        void toolStripMenuItemExit_Click(object sender, EventArgs e)
        {
            System.Windows.Application.Current.Shutdown();
        }

        private void notifyIcon1_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ShowWindow();
        }

        private void ShowWindow()
        {
            // ウィンドウ表示&最前面に持ってくる
            if (win.WindowState == System.Windows.WindowState.Minimized)
                win.WindowState = System.Windows.WindowState.Normal;

            win.Show();
            win.Activate();
            // タスクバーでの表示をする
            win.ShowInTaskbar = true;
        }

        //public NotifyIconWrapper(IContainer container)
        //{
        //    container.Add(this);

        //    InitializeComponent();
        //}
    }
}