25

I've been trying for hours to get to the point where I can start a WPF application and have full control. I want to be able to create a ViewModel, create a View (Window), set the data context of the View to be the ViewModel, then show the View.

I've tried lots of methods, the most promising being to change the App.xaml to be a page and then adding my own Main method. Unfortunately this doesn't work properly because VS2010 then does not show the styles from the App.xaml in the designer, though they do work when running the app.

Is there a way to do what I want? If not, how do people normally start MVVM apps in WPF, creating a ViewModel outside of the View itself?

Bill Jeeves
  • 493
  • 1
  • 7
  • 14
  • 1
    You can see the styles in the designer if you use DynamicResource in place of StaticResource. – amaca Aug 09 '10 at 13:20

4 Answers4

26

I would use the Startup event. You can add this to the App.xaml and remove the StartupUri line. When you add it, Visual Studio can create the event for you within the App.xaml.cs file. You can initialise your ViewModel and View within.

BlackWasp
  • 4,933
  • 2
  • 30
  • 42
  • 18
    Future readers, note that you need to assign a NEW event. DO NOT use the `protected override void OnStartup(StartupEventArgs e)` method, because there is a known bug in .NET 4.5 where the compiler cannot load Static Resources you've specified in the App.xaml. http://stackoverflow.com/questions/543414/wpf-app-xaml-file-does-not-get-parsed-if-my-app-does-not-set-a-startupuri – Riegardt Steyn Feb 05 '14 at 13:53
24

Here is one simple way...

<Application 
  x:Class="Demo.Ux.WpfApp.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>

Here is the basic App.xaml.cs

public partial class App
{
  protected override void OnStartup(StartupEventArgs e)
  {
    try
    {
      var mainView = new MainView();
      mainView.Show();
      mainView.DataContext = new MainViewModel();
    }
    catch (Exception ex)
    {
      Debug.WriteLine(ex);
    }
  }
}

Application.MainWindow can be used as well. The first displayed Window will be assigned to MainWindow auto-magically. Of course, you can skip creating your mainView and write directly to MainWindow which would thin out the syntax as well.

 MainWindow = new MainView();
 MainWindow.Show();
 MainWindow.DataContext = new MainViewModel();

One final note, I'm doing the Show before the data bind. You need to do this to avoid a situation where the MainViewModel throw an exception during creation. If the MainView hasn't been shown, the app will close without letting you see the error.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
visionarycoder
  • 385
  • 2
  • 7
  • 5
    !!! DON'T DO IT !!! You will definitely get into trouble if subsequently you'll want to add resources into App.xaml (see http://stackoverflow.com/questions/543414/wpf-app-xaml-file-does-not-get-parsed-if-my-app-does-not-set-a-startupuri) The accepted answer has no such a drawback. – Ilya Serbis Nov 24 '12 at 14:49
  • 1
    Lu55 - You can add resources to the App.xaml code without issues. It all depends on how much work you want to do. My understanding of the original question was: how to create a view and viewmodel with full control outside of the normal startupuri. If you want to wire everything up by hand. You can do it. Worrying about every possible variation of usage is just borrowing trouble. – visionarycoder Mar 26 '13 at 19:42
2

in our application, we have choosen the way which you already proposed: writing a new Main method. You also have to make some changes in the project application settings then (no startup object). The app xaml has to look something like this:

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

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>

            <!--Custom Controls-->
            <ResourceDictionary  Source="<your resources here>"/>


        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

The code behind will look something like this:

public sealed partial class App : Application
{
    static App()
    { }

    public App()
    { }

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // create the main window and assign your datacontext
        MainAppWindow main = new MainAppWindow();
        main.DataContext = <your datacontext here>
        main.Show();
    }

    [STAThreadAttribute]
    public static int Main(string[] args)
    {
        App app = new App();

        app.InitializeComponent();
        app.Run();

        return 0;
    }
}

Have a look at the Startup Event and notice, that no default StartupUri is specified im App.xaml

You could also pass the DataContext in a new constructor of your MainWindow, or create the DataContext directly in xaml.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
JanW
  • 1,799
  • 13
  • 23
1

The simplest way to assign an instance of the ViewModel to the DataContext of the view is in the code behind of the Window.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new myViewModel();
    }
}

For the first part of your question, you can have the control of your application in the StartUp event

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

    </Application.Resources>
</Application>

Code Behind :

public partial class App : Application
{
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // Place your code here
    }
}
Zied
  • 1,696
  • 12
  • 20
  • It all depends on what your view model needs to construct. If you've got an empty contructor this works fine. If you don't, it's not so pretty. – visionarycoder Mar 26 '13 at 19:26
  • I've started adding a ViewModel property to the ViewWindow w/ the needed composition decorations. The actual class for the VM is explicit, but all of my Views have a "ViewModel" property. So far, it's making life much easier while still respecting the boundary between the View and the ViewModel. I'm using a the Prism bootstrapper at this point, so I never let the App.xaml call to my shell by way of StartupUri. – visionarycoder Mar 26 '13 at 19:31