【WPF學習】第二十七章 Application類的任務

来源:https://www.cnblogs.com/Peter-Luo/archive/2020/02/05/12261010.html
-Advertisement-
Play Games

上一章介紹了有關WPF應用程式中使用Application對象的方式,接下來看一下如何使用Application對象來處理一些更普通的情況,接下倆介紹如何初始化界面、如何處理命名行參數、如何處理支付視窗之間的交互、如何添加跟蹤文檔以及如何創建單示例應用程式。 一、顯示初始化界面 WPF應用程式的運行 ...


  上一章介紹了有關WPF應用程式中使用Application對象的方式,接下來看一下如何使用Application對象來處理一些更普通的情況,接下倆介紹如何初始化界面、如何處理命名行參數、如何處理支付視窗之間的交互、如何添加跟蹤文檔以及如何創建單示例應用程式。

一、顯示初始化界面

   WPF應用程式的運行速度快,但並不能在瞬間啟動。當第一次啟動應用程式時,會有一些延遲,因為公共語言運行時(Common Language Runtime,CLR)首先需要初始化.NET環境,然後啟動應用程式。

  這一延遲未必成為問題。通常,只需要經歷很短的時間,就會出現第一個視窗,但如果具有更耗時的初始化步驟,或者如果只是希望通過顯示打開的圖像應用程式顯得更加專業,這時可使用WPF提供的簡單初始界面特性。

  下麵是添加初始界面的方法:

  (1)為項目添加圖像文件(通常是.bmp、.png或.jpg文件)。

  (2)在Solution Explorer中選擇圖像文件。

  (3)將Build Action修改為SplashScreen。

  下次運行應用程式時,圖像會立即在屏幕中央顯示出來。一旦準備好運行時環境。而且Application_Startup方法執行完畢,應用程式的第一個視窗就將顯示出來,這時初始化界面圖像會很快消失(約需300毫秒).

  該特性聽起來很簡單,事實上也確實如此。只需要記住顯示的初始化界面沒有任何裝飾,在它周圍沒有視窗邊框,所有由你決定是否為初始界面圖像添加邊框,也無法通過顯示一系列的多幅圖像或動畫讓初始化圖像顯得更富有想象力的效果。如果希望得到這種效果,需要採用傳統方法:創建在運行初始化代碼的同事顯示你所希望的圖像界面的啟動視窗。

  順便提一下,當添加初始界面時,WPF編譯器會自動生成的App.g.cs文件添加與下麵的類似的代碼:

SplashScreen splashScreen = new SplashScreen("images/blue.jpg");
//Show the splash screen
//The true parameter sets the splashScreen to fade away automatically
//after the first window appears
splashScreen.Show(true);

//Start the application
AssemblyResources.App app = new AssemblyResources.App();
app.InitializeComponent();
app.Run();
//The splash screen begins ites automatic fade-out now.

  也可自行編寫這一剪短邏輯,而不死使用SplashScreen 生成操作。但有一點需要指出,可以改變的唯一細節是初始界面褪去的速度。為此,需要項SplashScreen.Show()方法傳遞false(從而使WPF不會自動淡入初始化界面)。然後由你負責通過調用SplashScreen.Close()方法在恰當的時機隱藏初始界面,並提供TimeSpan值來指示經過多長時間淡出初始化界面。

二、處理命令行參數

  為處理命令行參數,需要相應Application.Startup事件。命令行參數是通過StartupEventArgs.Args屬性作為字元串數組提供的。

  例如,假定希望載入文檔,文檔名作為命令行參數傳遞。在這種情況下,有必要讀取命令行參數並執行所需的一些額外初始化操作。在下麵的示例中,通過響應Application.Startup事件實現了這一模式。在該例中,沒有在任何地方設置Application.StartupUri屬性——而是使用代碼實例化視窗。

public partial class App : Application
    {
        // The command-line argument is set through the Visual Studio
        // project properties (the Debug tab).
        private void App_Startup(object sender, StartupEventArgs e)
        {           
            // At this point, the main window has been created but not shown.
            FileViewer win = new FileViewer();

            if (e.Args.Length > 0)
            {
                string file = e.Args[0];
                if (File.Exists(file))
                {
                    // Configure the main window.                    
                    win.LoadFile(file);
                }
            }

            // This window will automatically be set as the Application.MainWindow.
            win.Show();
        }
    }
<Application x:Class="LoadFromCommandLine.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Startup="App_Startup">
    <Application.Resources>
         
    </Application.Resources>
</Application>
App.xaml

  上面的方法初始化主視窗,然後當App_Startup()方法結束是顯示主視窗。上面的代碼假定FileViewer類有名為LoadFile()的共有方法。這隻是一個示例,它只讀取並顯示指定文件的文本。

三、訪問當前Application對象

  通過靜態的Application.Current屬性,可在應用程式的任何位置獲取當前應用程式實例,從而在視窗之間進行基本交互,因為任何視窗都可以訪問當前Application對象,並通過Application對象,並通過Application對象獲取主視窗的作用:

Window main=Application.Current.MainWindow;
MessageBox.Show("The main window is "+main.Title);

  當然,如果希望訪問在自定義主視窗類中添加的任意方法、屬性或事件,需要將視窗對象轉換為正確類型。如果主視窗的自定義類MainWindow的實例,可使用與下麵類似的代碼:

MainWindow main=(MainWindow)Application.Current.MainWindow;
main.DoSomething();

  在視窗中還可以檢查Application.Windows集合的內容,該屬性提供了所有當前打開視窗的引用:

foreach(Window window in Application.Current.Windows)
{
    MessageBox.Show(window.Title+" is open.");
}

  實際上,大多數應用程式通常使用一種更具結構化特點的方式在視窗之間進行交互。如果有幾個長時間運行的視窗同事打開,並且它們之間需要以某種方式進行通信,在自定義應用程式類中保存這些視窗的引用可能更有意義。這樣,總可以找到所需的視窗。與此類似,如果有基於文檔的應用程式,那麼可選擇創建跟蹤文檔視窗的集合,而不是跟蹤其他內容。

四、在視窗之間進行交互

  整如在前面已經看到的,自定義應用程式類是放置響應不同應用程式事件的代碼的好地方。應用程式類還可以很好地達到另一個目的:保存重要視窗的引用,使一個視窗可訪問另一個視窗。

  例如,假設希望跟蹤應用程式使用的所有文檔視窗。為此,可在自定義應用程式類中創建專門的集合。下麵是使用泛型列表集合保存一組自定義視窗對象的示例。在這個示例中,每個文檔視窗由名為Document類的實例表示:

 public partial class App : Application
    {
        private List<Document> documents = new List<Document>();
        
        public List<Document> Documents
        {
            get { return documents; }
            set { documents = value; }
        }
    }

  現在,當創建新文檔時,只需要記住將其添加到Documents集合中即可。下麵是響應按鈕單擊事件的事件處理程式,該事件處理程式完成了所需的工作:

private void cmdCreate_Click(object sender, RoutedEventArgs e)
        {
            Document doc = new Document();
            doc.Owner = this;
            doc.Show();
            ((App)Application.Current).Documents.Add(doc);
        }

  同樣,也可在Document類中響應Window.Loaded類這些事件,以確保當創建文檔對象時,總會在Documents集合中註冊該文檔對象。

  現在,可在代碼的其他任何地方進行集合來遍歷所有文檔,並使用公有成員。在該例中,Document類包含用於更新顯示的自定義方法SetContent();

private void cmdUpdate_Click(object sender, RoutedEventArgs e)
        {
            foreach (Document doc in ((App)Application.Current).Documents)
            {
                doc.SetContent("Refreshed at " + DateTime.Now.ToLongTimeString() + ".");
            }            
        }
<Window x:Class="WindowTracker.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowTracker" Height="300" Width="300"
    >
    <StackPanel>
      <Button Click="cmdCreate_Click" Margin="10,10,10,5" Name="cmdCreate">Click to Create a Document</Button>
      <Button Click="cmdUpdate_Click" Margin="10,5,10,10" Name="cmdUpdate">Click to Refresh the Documents</Button>
    </StackPanel>
</Window>
MainWindow.xaml
<Window x:Class="WindowTracker.Document"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WindowTracker" Height="78" Width="209"
    >
    A new document.
</Window>
Document.xaml
public partial class Document : Window
    {
        public Document()
        {
            InitializeComponent();
        }

        public void SetContent(string content)
        {
            this.Content = content;
        }
    }
Document.xaml.cs

  下圖顯示了最終效果圖。最終結果談不上華美,但這種交互方式值得註意——演示了一種通過自定義應用程式類在視窗之間進行交互的安全規範的方式。這種方式比使用Window屬性要好,因為是強類型,只包含Document視窗(而不是包含視窗應用程式中所有視窗的集合)。通過這種方式還可使用另一種更有用的方式對視窗進行分類。例如,可使用字典集合,通過鍵名更方便地查找文檔。在基於文檔的引用程式中,可通過文件名來索引集合中的視窗。

 

 五、單實例應用程式

  通常,只要願意就可以載入WPF應用程式的任意多個副本。某些情況下, 這種設計時非常合理的。但在另外一些情況下,這可能會成為問題,當構建基於文檔的應用程式時更是如此。

  對於單實例應用程式,WPF本身並未提供自帶的解決方法,但可使用幾種變通方法。基本技術時當觸發Application.Startup事件時,檢查另一應用程式實例是否已在運行。最簡單的方法是使用全局的mutex對象(mutex對象時操作系統提供的用於進程間通信的同步對象)。這種方法很簡單,但功能有限。最重要的是,應用程式的新實例無法與已經存在的實例進行通信。對於基於文檔的應用程式而言這確實是一個問題,因為新實例可能需要告訴已經存在的應用程式實例打開某個特定的文檔(如果該文檔是通過命令行參數傳遞的)。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 要分析JVM的源碼,結合資料直接閱讀是一種方式,但是遇到一些想不通的場景,必須要結合調試,查看執行路徑以及參數具體的值,才能搞得明白。所以我們先來把JVM的源碼進行編譯,並能夠使用GDB進行調試。 編譯環境 本文使用的JDK版本:OpenJDK7,分支b147 下載頁面:https://downlo ...
  • numpy庫中矩陣的常用方法 1 矩陣轉置 從上圖可以看出:使用方法a.T可以將矩陣a轉置。 2 均值與方差 註意:方法a.mean()會對矩陣a的所有元素求均值,a.var()也是考慮矩陣a的所有元素求方差。 當然,也可以選取矩陣的某一行或某一列使用mean與var求均值與方差。 3 設置零矩陣 ...
  • java中棧記憶體與堆記憶體(JVM記憶體模型) Java中堆記憶體和棧記憶體詳解1 和 Java中堆記憶體和棧記憶體詳解2 都粗略講解了棧記憶體和堆記憶體的區別,以及代碼中哪些變數存儲在堆中、哪些存儲在棧中。記憶體中的堆和棧到底是什麼 詳細講述了程式在記憶體中的模型,從可執行文件(ELF)格式的編譯介紹了堆和棧,主要是... ...
  • 文件下載 1.開啟fileinfo擴展 2.fileinfo函數 finfo_open 創建一個fileinfo資源 finfo_close 關閉fileinfo資源 finfo_file 返回一個文件的信息 FILEINFO_MIME_TYPE 返回mime類型 FILEINFO_MIME_TYP ...
  • 平衡二叉樹(AVL樹)的自平衡(LL->R、RR->L、LR->LR、RL->RL)、增、刪 等操作。 main.cpp: #include <iostream> #include "AVLTree.h" using namespace std; int main() { AVLTree<int> ...
  • 用 C 寫一個 Redis 數據同步小工具 Intro 為了實現 redis 的數據遷移而寫的一個小工具,將一個實例中的 redis 數據同步到另外一個實例中。(原本打算找一個已有的工具去做,找了一個 nodejs 的小工具,結果折騰了好久都沒裝上。。。於是就自己寫了這個小工具) 之所以自己寫一個工 ...
  • WPF應用程式中的程式集資源與其他.NET應用程式中的程式集資源在本質上是相同的。基本概念是為項目添加文件,從而Visual studio可將其嵌入到編譯過的應用程式的EXE或DLL文件中。WPF程式集資源與其他應用程式中的程式集資源之間的重要區別是引用他們的定址系統不同。 在前面章節已討論過程式集 ...
  • 通過前兩章的內容,有了一定的基礎,但進入第三章,實例的步驟非常多,並且隨著VS版本的升級,部分功能菜單界面發生了很大變化,所以,第三章的案例我將逐步編寫! 實例3.1的目標就是給Excel寫一個載入巨集,實質就是寫一個Excel函數,並通過在註冊表中註冊,實現像自帶函數那樣的功能。 步驟一:Visua ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...