105

The question pretty much says it all.

I have a window, and have tried to set the DataContext using the full namespace to the ViewModel, but I seem to be doing something wrong.

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="BuildAssistantUI.ViewModels.MainViewModel">
Binil
  • 6,307
  • 3
  • 29
  • 40
Nicholas
  • 3,086
  • 4
  • 24
  • 35
  • Following up on Mike Nakis, I was trying to create the ViewModel manually and subscribe to events in it, only to find that the framework was creating another ViewModel. Hence the viewModel I was subscribed to was not the one attached to the view. – jlady Aug 27 '20 at 21:21
  • Does this mean that besides instantiating the viewmodel yourself, you were ***also*** specifying the type of the viewmodel in some other way ? A secondary advantage of viewmodels requiring constructor parameters is that the framework either cannot instantiate them, or it has to pass default values for those parameters, in which case you can easily detect instantiation by the framework. – Mike Nakis Aug 28 '20 at 08:13
  • The XAML designer might also need to be able to instantiate viewmodels, but this designer was never of any usefulness to me, (it just causes problems,) so I don't use it, so I personally do not care about that usage case. – Mike Nakis Aug 28 '20 at 08:13
  • `DataContext="{Binding Source={x:Type BuildAssistantUI.ViewModels.MainViewModel}}"` can we use like this {x:Type}?.. but, it is not working. – Vintage Coder Dec 22 '21 at 08:52

5 Answers5

158

Try this instead.

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:BuildAssistantUI.ViewModels">
    <Window.DataContext>
        <VM:MainViewModel />
    </Window.DataContext>
</Window>
Josh
  • 66,410
  • 14
  • 139
  • 154
  • 3
    I like this option the best. Seems cleaner if the VM is only used for the MainWindow. – Andrew Grothe Jan 29 '13 at 00:36
  • 13
    Is there a way to set the data context using an attribute on the `Window` element, like `DataContext="VM:MainWindowViewModel"`? – Oliver Mar 18 '14 at 15:21
  • This is the proper way! – JavierIEH Jul 26 '15 at 22:13
  • I am not completely understanding totally why one way is better than the other. Also, I do not totally see the difference in either of these ways in comparison to how I have seen some people use "Dynamic Resource". What is this? – Travis Tubbs Jun 05 '17 at 14:32
  • 2
    @Oliver you would have to implement `MarkupExtension`, never done it on VMs, but you could do it with converters to ensure only one instance of converter is present and call it direcly from xaml with `="{converters:SomethingConverter}"`, implying `xmlns:converters` points at converter namespace. `public abstract class BaseValueConverter : MarkupExtension, IValueConverter where T : class, new() { private static T _converter; public override object ProvideValue(IServiceProvider serviceProvider) { return _converter ?? (_converter = new T()); } }` – Whazz May 19 '18 at 22:30
  • Be aware that this mechanism only specifies **the type** of `MainViewModel`, not the instance of `MainViewModel`. This means that by using this construct you are giving WPF license to instantiate your `MainViewModel` by itself, which further requires that your `MainViewModel` must have a parameterless constructor. Furthermore, if you are also instantiating your `MainViewModel` somewhere, (say, in App.xaml.cs,) then there will be two instances of it, and your view will be interacting with only one of them. – Mike Nakis Aug 05 '20 at 13:50
122

In addition to the solution that other people provided (which are good, and correct), there is a way to specify the ViewModel in XAML, yet still separate the specific ViewModel from the View. Separating them is useful for when you want to write isolated test cases.

In App.xaml:

<Application
    x:Class="BuildAssistantUI.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BuildAssistantUI.ViewModels"
    StartupUri="MainWindow.xaml"
    >
    <Application.Resources>
        <local:MainViewModel x:Key="MainViewModel" />
    </Application.Resources>
</Application>

In MainWindow.xaml:

<Window x:Class="BuildAssistantUI.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{StaticResource MainViewModel}"
    />
Scott Weaver
  • 6,870
  • 2
  • 28
  • 40
Merlyn Morgan-Graham
  • 56,626
  • 16
  • 121
  • 179
  • Oh wow... thanks. I already marked this as answered, but your addition is much appreciated. Will use it. – Nicholas Jan 04 '11 at 04:10
  • @Nicholas: The other answer is perfect for the question, so I agree with your decision – Merlyn Morgan-Graham Jan 04 '11 at 04:15
  • 9
    Just be aware that this approach uses the same ViewModel instance for every instance of MainWindow. That's fine if the window is single-instance as this case implies, but not if you are showing multiple instances of the window such as in the case of a MDI or tabbed application. – Josh Jan 04 '11 at 04:27
  • 1
    Actually Josh's answer is better as it gives you type-safety on the DataContext. So you can bind directly to the DataContext without worrying about typo-ing some property name/path. – Josh M. Nov 04 '15 at 13:08
  • ` ` This works fine . but, i want like this inline `` – Vintage Coder Dec 22 '21 at 08:57
  • @VintageCoder I think you're trying to ask a new question? If so, go ahead and author a new separate question. I can't answer it though, cause I haven't done any XAML stuff for a decade now. – Merlyn Morgan-Graham Jan 13 '22 at 23:18
11

You need to instantiate the MainViewModel and set it as datacontext. In your statement it just consider it as string value.

     <Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BuildAssistantUI.ViewModels">
      <Window.DataContext>
        <local:MainViewModel/>
      </Window.DataContext>
Jobi Joy
  • 47,702
  • 20
  • 107
  • 119
5

There is also this way of specifying the viewmodel:

using Wpf = System.Windows;

public partial class App : Wpf.Application //your skeleton app already has this.
{
    protected override void OnStartup( Wpf.StartupEventArgs e ) //you need to add this.
    {
        base.OnStartup( e );
        MainWindow = new MainView();
        MainWindow.DataContext = new MainViewModel( e.Args );
        MainWindow.Show();
    }
}

<Rant>

All of the solutions previously proposed require that MainViewModel must have a parameterless constructor.

Microsoft is under the impression that systems can be built using parameterless constructors. If you are also under that impression, go ahead and use some of the other solutions.

For those that know that constructors must have parameters, and therefore the instantiation of objects cannot be left in the hands of magic frameworks, the proper way of specifying the viewmodel is the one I showed above.

</Rant>

Mike Nakis
  • 50,434
  • 8
  • 92
  • 124
  • What if I have a `` with a MainView and a MainViewModel - here I don't have an `OnStartup` event, this is actually what I'm looking into right now... – PandaWood Jul 31 '21 at 13:59
  • @PandaWood I do not follow you. Is your `UserControl` (lets call it `MyUserControl`) the root visual of the application, or does it live inside a window? In either case, `MyUserControl` ***is*** a view, so it is unclear how that other `MainView` fits into the picture. – Mike Nakis Aug 01 '21 at 10:46
  • If `MyUserControl` is supposed to live inside another view, (say, inside `MyMainView`,) then `MyMainViewModel` would have a `MyUserControlViewModel` member property, so in `MainWindowView` you would just say ``. – Mike Nakis Aug 01 '21 at 10:48
  • Note that `MyUserControlViewModel` lives inside `MyMainViewModel`, so `MyMainViewModel` instantiates it, so it can pass to it whatever constructor parameters it needs. – Mike Nakis Aug 01 '21 at 10:49
3

You might want to try Catel. It allows you to define a DataWindow class (instead of Window), and that class automatically creates the view model for you. This way, you can use the declaration of the ViewModel as you did in your original post, and the view model will still be created and set as DataContext.

See this article for an example.

Geert van Horrik
  • 5,504
  • 1
  • 17
  • 32