views:

2784

answers:

4

Background: I'm creating a WPF app using MVVM, and using a DI container to build my ViewModels

My App.xaml looks like this:

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

MainWindow.xaml looks like this:

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

Now, this all works fine, but the StartupUri is hardcoded into the XAML, which I don't want.
Following guidance of several blogposts and articles I found, I removed the StartupUri, and tried to create the MainWindow by hooking OnStartup in App.xaml.cs, like this:

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

The problem is, the app crashes when trying to show the window, with this exception:

Cannot find resource named '{serviceLocator}'. Resource names are case sensitive. Error at object 'System.Windows.Data.Binding' in markup file 'WpfApp;component/mainwindow.xaml' Line 8 Position 45.

As far as I can tell, the <Application.Resources> section is simply not being read out of the xaml file. I can put some code in the OnStartup to add the resource programatically like this:

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

However that's an ugly hack, and doesn't help me if I wanted to put something else in the app.xaml file later on :-(

Should I be hooking some other event? Is there a way around this?

Thanks, Orion.

A: 

I have tried to replicate your problem, but everything seems to work fine on my side. I'm using 3.5 SP1. Have you tried with DynamicResource markup extension instead?

ligaz
+11  A: 

Rather than overriding OnStartup, try using an event instead:

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

Code behind:

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();
    }
}
Nidonocu
This solves it, thanks!
Orion Edwards
A: 

I've run into a similar/this same issue. There's a VS code generation bug where the code necessary to connect <Application.Resources> to the rest of the program sometimes is not inserted when <Application.Resources> contains only one entry and does not have a StartupUri attribute.

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

Ben Gribaudo
A: 

The most simple workaround is the definition of a x:Name:

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

More information: http://connect.microsoft.com/VisualStudio/feedback/details/472729/wpf-cannot-find-resource-defined-in-the-app-xaml-file

jbe