2011-05-27 62 views
49

WPF定義了自己的Main()方法。我應該如何去與(正常)打開WPF MainWindow我自己Main方法取代它(例如添加通過命令行參數的非WPF腳本模式)?更換WPF切入點

回答

48

一些例子描繪改變從ApplicationDefinition App.xaml中的生成操作Page,並編寫自己的Main()來實例化App類,並調用其Run()方法,但是這可能會產生的一些不必要的後果解析App.xaml中的應用程序範圍資源。

相反,我建議您在自己的類製作自己的Main(),並在項目屬性啓動對象設置爲該類:

public class EntryPoint { 
    [STAThread] 
    public static void Main(string[] args) { 
     if (args != null && args.Length > 0) { 
      // ... 
     } else { 
      var app = new App(); 
      app.InitializeComponent(); 
      app.Run(); 
     } 
    } 
} 

我這樣做是爲了採取一些AppDomain事件必須是優勢在發生任何事情之前訂閱(例如AssemblyResolve)。我經歷過的App.xaml設置爲Page的不良後果包括我UserControl意見(M-V-VM)不解決在設計時在App.xaml中佔用的資源。

+0

好的,我調用App.Main()而不是Run(),因爲Main()調用了InitializeComponent(),它安裝了Startup事件處理程序。我猜你必須調用Run(),如果你將Build Action更改爲Page(因爲Main()消失),但我只是將它作爲ApplicationDefinition保留。 – Qwertie 2011-05-31 23:53:45

+2

生成的Main()只是實例化App,並調用Run()。 'Startup'事件在'System.Windows.Application'的構造函數中觸發。 'Run()'附加一個'Dispatcher'並開始消息泵。 ''InitializeComponent()'應該在'Apps'的構造函數中調用。不是嗎? – 2011-06-01 02:43:10

+0

不,應用程序的微軟生成代碼不包含構造函數,所以應調用App.Main()以調用InitializeComponent()和Run()。我使用VS2008/.NET3.5,如果這有所作爲。請注意,System.Windows.Application本身不能調用InitializeComponent,因爲InitializeComponent只存在於派生類中,並且是非虛擬的。它也不會觸發啓動事件,因爲任何人都不可能在構造函數返回之前訂閱了該事件。 – Qwertie 2011-11-10 23:35:06

19

通常我編輯App.xaml添加這個支持:

<Application x:Class="SomeNamespace.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Startup="Application_Startup"> 

相關的部分是我從StartupUri變更爲Startup與事件處理程序App.xaml.cs。這裏有一個例子:

/// <summary> 
/// Interaction logic for App.xaml 
/// </summary> 
public partial class App : Application 
{ 
    private void Application_Startup(object sender, StartupEventArgs e) 
    { 
     int verbose = 0; 
     var optionSet = new OptionSet 
     { 
      { "v|verbose", "verbose output, repeat for more verbosity.", 
        arg => verbose++ } 
     }; 

     var extra = optionSet.Parse(e.Args); 
     var mainWindow = new MainWindow(verbose); 
     mainWindow.Show(); 
    } 
} 
+0

雖然,除非你從一個命令窗口運行它,你將看不到任何'Console。*'輸出。 – user7116 2011-05-27 19:04:02

+0

這種方法讓我將構造函數參數傳遞給主窗口,這很好。我甚至可能會把它和喬爾的方法結合起來。 – Qwertie 2011-05-27 19:46:46

+0

感謝您指出它是「啓動」而不是「StartupUri」! – 2017-02-01 19:24:06

2

與自定義靜態Main方法創建新類。在這個方法結束只需要調用原來App.Main()的WPF產生:

public class Program 
{ 
    [STAThread] 
    public static void Main(string[] args) 
    { 
     // Your initialization code 
     App.Main(); 
    } 
} 

然後設置項目的「啓動對象」設置爲包含您的靜態Main()的類。

11

傢伙 的問題是,你的程序有兩個靜態Main()方法,這將導致編譯器之間的抱怨;要解決這個問題,嘗試下列操作之一:

  • 告訴編譯器,你的靜態Main()方法應該是執行入口點設置項目的「啓動對象」設置爲包含您的靜態Main類()方法(右鍵單擊解決方案資源管理器中的項目,選擇「屬性」,然後在「應用程序」選項卡下查找「啓動對象」設置)。
  • 關閉自動生成App.g.cs的靜態Main()方法,在解決方案資源管理中,右鍵單擊App.xaml中,選擇「屬性」,然後更改從「ApplicationDefinition」到「頁中的「生成操作」 」。
+1

謝謝;第二個重點是關鍵 - 巧妙地放在那裏! – Jeb 2016-12-01 16:04:04

0

使用自定義Main()可能會遇到問題,因爲StartupUri未設置。

你可以用它來設置,而無需在App類頭痛(不要忘記從App.xaml中刪除的StartupUri並設置其生成操作頁面):使用這種方法

[STAThread] 
static void Main() 
{ 
    App app = new App(); 
    app.InitializeComponent(); 
    app.Run(); 
} 

protected void OnStartup(object sender, StartupEventArgs e) 
{ 
     var toUri = new UriTypeConverter(); 
     StartupUri = (Uri)toUri.ConvertFrom("MainWindow.xaml"); 
... 
}