WPF:Mainメソッドを書き変えるには?[C#/VB]:.NET TIPS
WPFアプリのMainメソッドは通常、自動生成される。本稿では、Mainメソッドの自動生成をやめ、独自の処理を行うように書き換える方法を解説する。
対象:.NET 3.0以降
WPFでも、Mainメソッドを書き換えたいときがあるだろう。WPFの初期化処理が始まる前に何らかの処理を行いたいというときだ。コンソールプログラムならMainメソッドから書き始めるので、何の問題もない。Windowsフォームでは、Mainメソッドを記述したクラスをプロジェクトのプロパティで[スタートアップ オブジェクト]に指定すればよかった(参照:「.NET TIPS:VB.NETでアプリケーション起動時に実行されるフォームを変更するには?」/「.NET TIPS:C#でアプリケーション起動時に実行されるフォームを変更するには?」)。では、WPFではどのようにすればよいのだろうか? 本稿では、その方法を解説する。
Mainメソッドの自動生成を止めるには?
WPFも、Windowsフォームと同様に、プロジェクトのプロパティで[スタートアップ オブジェクト]を指定できる*1。WPFの場合、既定ではAppクラス(C#)/Applicationクラス(VB)がスタートアップオブジェクトになっている。そして、WPFではそれらのクラスにMainメソッドが自動生成されるのである。それを確かめるには、Appクラス(C#)/Applicationクラス(VB)をコードエディターで開いて、上部のドロップダウンを開いてみると分かる(次の画像)。
*1 VBでは、[スタートアップ オブジェクト]の指定は少々分かりにくい。まず、[スタートアップ オブジェクト]を指定するには、[アプリケーション フレームワークを有効にする]のチェックを外す必要がある。チェックを外してみると[スタートアップ オブジェクト]には既定として[Sub Main]と表示されるが、ここで確認するようにそれはApplicationクラス内に自動生成されるものだ。ただし、今の段階でこのチェックを外してしまうと、自動生成されるMainメソッドを確認できなくなる。なお、この後、「Application.xaml」ファイルに対するビルドアクションを変更した時点で、このチェックは自動的に外れる。
WPFのMainメソッドを確認する(上:C#、下:VB)
Appクラス(C#)/Applicationクラス(VB)をコードエディターで開き、上部の左側のドロップダウンでAppクラス(C#)/Applicationクラス(VB)を選択し、右側のドロップダウンを開いてみると、Mainメソッドが存在している(赤枠内)。それを選ぶと、自動生成されたMainメソッドが表示される。
なお、この画像はVisual Studio Express 2012のものだが、他のバージョンのVisual Studioでもほぼ同様である(本稿執筆時点では、Visual Studio 2010までのメインストリームサポート期間は終了している)。クラスを選択するドロップダウンは、Visual Studio 2013からは左側ではなく中央に移っている。
このドロップダウンで[Main]を選択すると、自動生成されたMainメソッドが表示される。では、それを書き換えればよいかというと、そうはいかないのである。ビルドするたびに、自動生成コードで上書きされてしまうからだ。
そこで、まずはMainメソッドの自動生成を止めなければならない。それには、「App.xaml」ファイル(C#)/「Application.xaml」ファイル(VB)に対するビルドアクションを、他のXAMLファイルと同じく[Page]に変更すればよい(次の画像)。
Mainメソッドの自動生成を止める
Visual Studioのソリューションエクスプローラーで「App.xaml」ファイル(C#)/「Application.xaml」ファイル(VB)を選択し(赤枠内)、プロパティペインの[ビルド アクション]を[ApplicationDefinition]から[Page](赤丸内)に変更する。
なお、これだけではビルドエラーになる。自動生成されていたMainメソッドが存在しなくなったためだ。
Mainメソッドを追加するには?
続いて、Mainメソッドを追加する。「App.xaml.cs」ファイル(C#)/「Application.xaml.cs」ファイル(VB)を開いて、次のようなコードを追加すればよい。ただし、C#はこれだけでよいが、VBではビルドエラーになる(対応は後述)。
public partial class App : Application
{
[STAThread]
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.Run();
}
}
Class Application
<STAThread> _
Public Shared Sub Main()
Dim app As Application = New Application()
app.InitializeComponent()
app.Run()
End Sub
End Class
太字の部分を追加した。
自動生成されていたMainメソッドとほぼ同じコードだ。違いは、メソッドに付ける属性を最低限に減らしたくらいである。
MainメソッドにはSTAThread属性を付けなければならない(Windowsフォームと同様)。
Mainメソッドでは、Appクラス(C#)/Applicationクラス(VB)のインスタンスを作成し、そのInitializeComponentメソッドを呼び出してから、Runメソッドを呼び出す。
なお、VBでは、このコードではビルドエラーになる(次で説明する初期表示ウィンドウを指定するコードが必要)。
初期表示ウィンドウを変更するには?
プログラムの起動時に、何らかの条件(例えばコマンドライン引数など)によって最初に表示されるウィンドウを切り替えたいこともあるだろう。それをやってみよう。
この初期表示ウィンドウは、既定では「App.xaml」ファイル(C#)/「Application.xaml」ファイル(VB)に記述されている(次のコード)。
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
太字の部分が、最初に表示されるウィンドウを指定している部分。これからこの部分を削除し、Mainメソッドのコードに記述を移す。
これは「Application.xaml」ファイル(VB)の例だが、「App.xaml」ファイル(C#)も同様である。
なお、太字の部分を削除するとVBのコードもビルドできるようになる(ただし、実行しても何も表示されない)。
上のコードの「StartupUri="MainWindow.xaml"」の部分を削除し、先ほど作成したMainメソッドを次のコードのように書き換える。
[STAThread]
public static void Main()
{
App app = new App();
app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
app.InitializeComponent();
app.Run();
}
<STAThread> _
Public Shared Sub Main()
Dim app As Application = New Application()
app.StartupUri = New Uri("MainWindow.xaml", UriKind.Relative)
app.InitializeComponent()
app.Run()
End Sub
太字の部分を追加した。
これで、VBでもビルド/実行できるようになる。
これでビルドして実行してみてほしい。ちゃんと「MainWindow.xaml」ウィンドウが表示されるはずだ。Mainメソッドを書き換えられるようにするという目標は、VBでも達成できた。
次にMainメソッドで初期表示ウィンドウを切り替えてみよう。プロジェクトにウィンドウを一つ追加してもらいたい。ファイル名は「SecondWindow.xaml」とする。プログラムの起動時にメッセージボックスを出し、エンドユーザーの応答によって初期表示ウィンドウを切り替えるコードは、次のように書ける。
[STAThread]
public static void Main()
{
var result = MessageBox.Show("SecondWindowを起動しますか?",
".NET TIPS #1119",
MessageBoxButton.YesNoCancel);
if (result == MessageBoxResult.Cancel)
return; // プログラム終了
App app = new App();
if (result == MessageBoxResult.Yes)
app.StartupUri = new Uri("SecondWindow.xaml", UriKind.Relative);
else
app.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
app.InitializeComponent();
app.Run();
}
<STAThread> _
Public Shared Sub Main()
Dim result = MessageBox.Show("SecondWindowを起動しますか?",
".NET TIPS #1119",
MessageBoxButton.YesNoCancel)
If (result = MessageBoxResult.Cancel) Then
Return ' プログラム終了
End If
Dim app As Application = New Application()
If (result = MessageBoxResult.Yes) Then
app.StartupUri = New Uri("SecondWindow.xaml", UriKind.Relative)
Else
app.StartupUri = New Uri("MainWindow.xaml", UriKind.Relative)
End If
app.InitializeComponent()
app.Run()
End Sub
太字の部分を追加した。
コメントに「プログラム終了」とある部分でプログラムを終了した場合は、Appクラス(C#)/Applicationクラス(VB)の初期化処理が一切実行されない(インスタンスさえ生成されない)。起動時の条件によってAppクラス(C#)/Applicationクラス(VB)のコンストラクターを実行したくないことがある場合は、このようにしてMainメソッドに記述するしかないのである(Appクラス(C#)/Applicationクラス(VB)のStartupイベントを利用した場合は、コンストラクターは実行されてしまう)。
なお、このVBのコードは、Visual Basic 2010から利用できるようになった「暗黙の行連結」を使用している。Visual Basic 2010以前の環境で試すには、適宜修正していただきたい。
上のコードを実行すると、次の画像のようなメッセージボックスが表示される。[はい]ボタンをクリックすると「SecondWindow.xaml」のウィンドウが表示され、[いいえ]ボタンでは「MainWindow.xaml」のウィンドウが表示される。[キャンセル]ボタンでは、直ちにプログラムが終了する。
Mainメソッドから出したメッセージボックス
このようにMainメソッドでメッセージボックスを出せる。Appクラス(C#)/Applicationクラス(VB)のインスタンスを生成する前であっても、UIを表示できるのだ。
まとめ
WPFでMainメソッドを書き変えるには、まず、「App.xaml」ファイル(C#)/「Application.xaml」ファイル(VB)の[ビルド アクション]を[Page]に変更し、それから、「App.xaml.cs」ファイル(C#)/「Application.xaml.cs」ファイル(VB)にMainメソッドを書き加える。VBでは、さらに、初期表示ウィンドウの指定をXAMLからMainメソッドに移す必要がある。
Mainメソッドのコーディングには、Appクラス(C#)/Applicationクラス(VB)の初期化処理が始まる前に任意の処理を実行できるというメリットがある。
利用可能バージョン:.NET Framework 3.0以降
カテゴリ:Visual Studio 処理対象:プロジェクト
カテゴリ:WPF/XAML 処理対象:アプリケーション
使用ライブラリ:Applicationクラス(System.Windows名前空間)
関連TIPS:VB.NETでアプリケーション起動時に実行されるフォームを変更するには?
関連TIPS:C#でアプリケーション起動時に実行されるフォームを変更するには?
関連TIPS:WPFでコマンドライン引数を取得するには?[C#、VB、2.0、3.0、3.5]
Copyright© Digital Advantage Corp. All Rights Reserved.