2011-05-27 18 views
49

WPF define su propio método Main(). ¿Cómo debo reemplazarlo con mi propio método Main que (normalmente) abre WPF MainWindow (por ejemplo, para agregar un modo de escritura que no sea WPF mediante argumentos de línea de comandos)?Reemplazar el punto de entrada WPF

Respuesta

48

Algunos ejemplos ilustran el cambio de Acción de generación de App.xaml de ApplicationDefinition a Page y escribir su propio Main() que instancia la clase App y llama a su método Run(), pero esto puede producir algunas consecuencias no deseadas en el resolución de recursos de toda la aplicación en App.xaml.

En cambio, sugiero hacer su propio Main() en su propia clase y establecer el objeto inicial de esa clase en las propiedades del proyecto:

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(); 
     } 
    } 
} 

Lo hago para aprovechar algunas AppDomain eventos que deben estar suscrito antes de que pase cualquier otra cosa (como AssemblyResolve). Las consecuencias no deseadas de configurar App.xaml en Page que experimenté incluyen mis UserControl Vistas (M-V-VM) que no resuelven los recursos almacenados en App.xaml durante el tiempo de diseño.

+0

De acuerdo, llamo a App.Main() en lugar de Run() porque Main() llama a InitializeComponent(), que instala el controlador de eventos de inicio. Supongo que debes llamar a Run() si cambias Build Action por Page (ya que Main() desaparece), pero lo dejé como ApplicationDefinition. – Qwertie

+2

El 'Main()' generado genera una 'App' y llama a 'Run()'. El evento 'Startup' se activa en el constructor' System.Windows.Application'. 'Run()' conecta un 'Dispatcher' y comienza la bomba de mensajes. 'InitializeComponent()' debería llamarse en el constructor 'Apps'. ¿No lo es? –

+0

No, el código generado por microsoft para la aplicación no incluye un constructor, por lo que debe llamarse a App.Main() para llamar tanto a InitializeComponent() como a Run(). Estoy usando VS2008/.NET3.5, si eso hace la diferencia. Tenga en cuenta que System.Windows.Application en sí no puede llamar a InitializeComponent, porque InitializeComponent solo existe en la clase derivada y no es virtual. Tampoco activará el evento de inicio porque no es posible que alguien se haya suscrito a ese evento hasta después de que el constructor regrese. – Qwertie

19

Normalmente edito App.xaml añadir este soporte:

<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"> 

La parte pertinente de ser pasé de StartupUri a Startup con un controlador de eventos en App.xaml.cs. He aquí un ejemplo:

/// <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

Aunque con este enfoque, a menos lo ejecuta desde una ventana de comandos, no verá ningún resultado 'Console '. *. – user7116

+0

Este enfoque me permite pasar argumentos de constructor a la ventana principal, lo cual es bueno. Incluso podría combinarlo con el enfoque de Joel. – Qwertie

+0

¡Gracias por señalar que es "Inicio" y no "StartupUri"! –

2

Crea una nueva clase con tu método principal estático personalizado. Al final de este método sólo llamar App.Main originales() generado por WPF:

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

Después ajuste “Objeto inicial” de su proyecto de establecer a la clase que contiene su estática Principal().

11

guys El problema es que su programa tiene dos métodos Main() estáticos, que causarán que el compilador se queje entre; Para resolver este problema, pruebe uno de los siguientes:

  • indicar al compilador que el método de su estática Principal() debe ser “objeto inicial” de la entrada ejecución en el punto Conjunto de tu proyecto de establecer a la clase que contiene su estática Principal() método (haga clic derecho en el proyecto en el Explorador de soluciones, elija "Propiedades", luego busque la opción "Objeto de inicio" en la pestaña "Aplicación").
  • Desactivar la generación automática del método Main() estático de App.g.cs: en el Explorador de soluciones, haga clic con el botón secundario en App.xaml, elija "Propiedades" y luego cambie "Acción de compilación" de "Definición de aplicación" a "Página ".
+1

Gracias; El segundo punto era crucial, sutilmente guardado allí. – Jeb

0

Al utilizar un Main() personalizado, es posible que tenga problemas porque StartupUri no está configurado.

Usted puede usar esto para configurarlo y sin dolores de cabeza en su clase de aplicación (No se olvide de quitar StartupUri de App.xaml y establecer su Acción de generación de Página):

[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"); 
... 
} 
Cuestiones relacionadas