介紹
就像每一個窗口對應一個Window類一樣,每一個WPF的應用程序對應一個Application類
生命週期
創建
WPF程序中,Application類的創建是由App.xaml中完成的,具體的代碼如下
<Application x:Class="TestProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Novc.ViPlex.Express" DispatcherUnhandledException="Application_DispatcherUnhandledException"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Themes/Converters.xaml"/>
<ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Themes/Default/Generic.xaml"/>
<ResourceDictionary Source="/Novc.ViPlex.Express.Views;component/Language/Language.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
其中比較關鍵的是指定了StartupUri
關閉
- 在xaml中可以設置ShutdownMode
- 手動關閉應用程序需要:Application.Shutdown()
事件處理
我們可以在App.xaml.cs中監聽下面的事件
事件的處理可以有兩種方法,一種是在xaml中指定事件處理程序,就像給一個Button寫OnClick一樣,一種是直接在App.xaml.cs中複寫相應的事件處理程序,比如重寫OnStartUp
// 1. 關聯事件處理程序
// xaml
DispatcherUnhandledException="Application_DispatcherUnhandledException"
// cs文件
private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
...
}
// 2. 直接複寫
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
}
- 需要注意 Application_DispatcherUnhandledException 這個方法沒有對應的基類方法可以複寫,只能通過xaml關聯
- OnSessionEnding方法如果監聽,設置e.Cancel = true,則系統的關閉,註銷都會被阻止。
顯示初始Load圖片
在出現第一個窗口之前,我們可以設置一個圖片作爲過場加載動畫,做法是:
- 項目中加載一個圖片
- 設置圖片屬性,將 生成操作 屬性修改爲SplashScreen
處理命令行參數
我們的程序可以直接右鍵打開,也可以在命令行中添加命令打開。要想獲取命令行參數,需要在App_Satrtup事件中,使用StartEventArgs參數e,e.Args[0]獲取第一個參數。
Application的用處
獲取窗口實例
// 獲取應用程序實例
Application.Current
// 獲取主窗體
Application.Current.MainWindow
// 所有打開的窗口引用,注意窗口在集合中的位置不是固定的,不能通過一個數字索引來確定窗體
Application.Current.Windows
窗口間信息交互
- 在Application類中可以保存重要窗口的引用,使得另一個窗口可以訪問他
// App類中可以保存全局的引用
// 定義
prop List<Document> Documents
// 在程序中任意位置使用
((App)Application.Current).Documents
// 在使用的時候可以把Document作爲所有要跟蹤的窗口的基類
單例應用程序
如果我們的應用程序只能打開一份,比較容易想到的方法是在StartUp方法中,判斷是否有應用程序已經打開,可以判斷進程,並且關閉本軟件。但是這種方法無法實現像word那樣,打開doc文件如果office已經打開就在當前實例中打開這個文件,原因是按照我們原來的方法,當打開軟件走到StartUp的時候,已經是新的應用程序了。要實現這樣的功能我們需要這樣的方法:
- 添加對於Microsoft.VisualBasic.dll的引用
- 新增一個類,繼承自 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
- 構造函數中設置IsSingleInstance爲true
- 複寫OnStartUp方法,創建WPF對象
- 複寫OnStartupNextInstance方法,調用原來的WPF APP去處理該方法中的啓動參數
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
string extension = ".testDoc";
string title = "SingleInstanceApplication";
string extensionDescription = "A Test Document";
// Uncomment this line to create the file registration.
// In Windows Vista, you'll need to run the application
// as an administrator.
//FileRegistrationHelper.SetFileAssociation(
// extension, title + "." + extensionDescription);
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}
WPfApp類代碼:
public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
// An ObservableCollection is a List that provides notification
// when items are added, deleted, or removed. It's preferred for data binding.
private ObservableCollection<DocumentReference> documents =
new ObservableCollection<DocumentReference>();
public ObservableCollection<DocumentReference> Documents
{
get { return documents; }
set { documents = value; }
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
DocumentReference docRef = new DocumentReference(doc, filename);
doc.LoadFile(docRef);
doc.Owner = this.MainWindow;
doc.Show();
doc.Activate();
Documents.Add(docRef);
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}
使用StartUp啓動應用程序:
public class Startup
{
[STAThread]
public static void Main(string[] args)
{
SingleInstanceApplicationWrapper wrapper = new SingleInstanceApplicationWrapper();
wrapper.Run(args);
}
}
不需要傳遞參數的單例應用程序
如果只需要在多開的時候關閉當前應用並且將之前的激活,用下面的方法即可
private void App_Startup(object sender, StartupEventArgs e)
{
//獲取欲啓動進程名
string strProcessName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
//檢查進程是否已經啓動,已經啓動則顯示提示退出程序。
if (System.Diagnostics.Process.GetProcessesByName(strProcessName).Length > 1)
{
RaiseOtherProcess();
Application.Current.Shutdown();
return;
}
Platform.Log.LogForNet.LogHelper.Init();
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
/// <summary>
/// 激活已打開窗口
/// </summary>
public static void RaiseOtherProcess()
{
Process proc = Process.GetCurrentProcess();
foreach (Process otherProc in
Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName))
{
if (proc.Id != otherProc.Id)
{
IntPtr hWnd = otherProc.MainWindowHandle;
if (IsIconic(hWnd))
{
ShowWindowAsync(hWnd, 9);
}
SetForegroundWindow(hWnd);
break;
}
}
}