47 votes

WPF - Le fichier App.xaml n'est pas analysé si mon application ne définit pas de StartupUri ?

Le contexte : Je crée une application WPF en utilisant MVVM et j'utilise un conteneur DI pour construire mes ViewModels.

Mon App.xaml ressemble à ceci :

<Application x:Class="WpfApp.App"
    ...xmlns etc...
    StartupUri="MainWindow.xaml">
    <Application.Resources>
        <app:ServiceLocator x:Key="serviceLocator" />
    </Application.Resources>
</Application>

MainWindow.xaml ressemble à ceci :

<Window x:Class="CompositeMefWpfApp.MainWindow"
    ...xmlns etc... >
    <Control.DataContext>
        <Binding Path="MainWindowViewModel" Source="{StaticResource serviceLocator}" />
    </Control.DataContext>

Maintenant, tout cela fonctionne bien, mais le StartupUri est codé en dur dans le XAML, ce que je ne veux pas.
En suivant les conseils de plusieurs articles de blog et d'articles que j'ai trouvés, j'ai supprimé la StartupUri et a essayé de créer le MainWindow par crochetage OnStartup dans App.xaml.cs, comme ceci :

protected override void OnStartup( StartupEventArgs e )
{
    base.OnStartup(e);
    new MainWindow().Show();
}

Le problème est que l'application se plante lorsqu'elle essaie d'afficher la fenêtre, avec cette exception :

Impossible de trouver la ressource nommée '{serviceLocator}'. Les noms de ressources sont sensibles à la casse. Erreur au niveau de l'objet 'System.Windows.Data.Binding' dans le fichier de balisage 'WpfApp;component/mainwindow.xaml' Ligne 8 Position 45.

D'après ce que je sais, le <Application.Resources> n'est tout simplement pas lue dans le fichier xaml. Je peux mettre du code dans le OnStartup pour ajouter la ressource de façon programmatique comme ceci :

Resources.BeginInit();
Resources.Add("serviceLocator", new ServiceLocator());
Resources.EndInit();

Cependant, ce n'est pas très pratique et cela ne m'aide pas si je veux ajouter quelque chose d'autre dans le fichier app.xaml par la suite.

Devrais-je accrocher un autre événement ? Existe-t-il un moyen de contourner ce problème ?

Merci, Orion.

55voto

Nidonocu Points 3580

Plutôt que de remplacer OnStartup, essayez d'utiliser un événement à la place :

<Application x:Class="My.App"
    xmlns="..."
    Startup="Application_Startup"
    ShutdownMode="OnExplicitShutdown">
        <Application.Resources>
            <app:ServiceLocator x:Key="serviceLocator" />
        </Application.Resources>
    </Application>

Code derrière :

public partial class App : Application
{
    public App()
    { }
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // TODO: Parse commandline arguments and other startup work 
        new MainWindow().Show();
    }
}

26voto

jbe Points 4629

La solution de contournement la plus simple est la définition d'un fichier x:Nom :

<Application x:Name="App" ...
    <Application.Resources>
        ...
    </Application.Resources>
</Application>

Plus d'informations : http://connect.microsoft.com/VisualStudio/feedback/details/472729/wpf-cannot-find-resource-defined-in-the-app-xaml-file

13voto

Ben Gribaudo Points 2023

J'ai rencontré un problème similaire/identique. Il y a un bug de génération de code VS où le code nécessaire pour connecter <Application.Resources> au reste du programme n'est parfois pas inséré lorsque <Application.Resources> ne contient qu'une seule entrée et n'a pas de StartupUri attribut.

Détails : http://bengribaudo.com/blog/2010/08/19/106/bug-single-application-resources-entry-ignored

2voto

user1412631 Points 16

Pour contourner ce bogue, vous pouvez également ajouter des ressources de manière programmatique.

var rd = new ResourceDictionary()
rd.Source = new Uri("pack://application:,,,/Resources;component/Colors.xaml");
Resources.MergedDictionaries.Add(rd);

Ce code peut être placé à l'intérieur du constructeur pour l'élément d'information. App classe.

-1voto

ligaz Points 1683

J'ai essayé de reproduire votre problème, mais tout semble fonctionner correctement de mon côté. J'utilise la version 3.5 SP1. Avez-vous essayé d'utiliser l'extension de balisage DynamicResource à la place ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X