What is the advantage of setting DataContext in code instead of XAML?
Asked Answered
P

7

14

There seem to be two main ways to define DataContext in WPF:

  • either in code like this:

App.xaml.cs (taken from the WPF MVVM Toolkit template):

public partial class App : Application
{
    private void OnStartup(object sender, StartupEventArgs e)
    {
        // Create the ViewModel and expose it using the View's DataContext
        MainView mainView = new MainView();
        MainViewModel mainViewModel = new MainViewModel();
        mainViewModel.LoadCustomers("c:\\testdata2\\Customers.xml");
        mainView.DataContext = mainViewModel;
        mainView.Show();
    }
}
  • or in XAML like this:

Window1.xaml:

<DockPanel>
    <StackPanel
        HorizontalAlignment="Left"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <StackPanel.DataContext>
            <local:CustomerViewModel />
        </StackPanel.DataContext>
        <TextBlock Text="{Binding Path=FirstName}" />
        <TextBlock Text=" " />
        <TextBlock Text="{Binding Path=LastName}" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <ListBox ItemsSource="{Binding Source={StaticResource FileNames}}" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <ComboBox
            ItemsSource="{Binding Source={StaticResource Directories}}"
            SelectedIndex="0" />
    </StackPanel>

    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="top"
        DockPanel.Dock="Top"
        Orientation="Horizontal">
        <StackPanel.DataContext>
            <local:SystemInformationViewModel />
        </StackPanel.DataContext>
        <TextBlock Text="{Binding Path=CurrentTime}" />
    </StackPanel>
</DockPanel>

One advantage that defining the DataContext in XAML has is that your data shows up in Expression Blend design mode and Expression Blend allows you to do quite a lot within the GUI e.g. choose fields from your datasource, etc. as shown here.

I have read that binding ADO.NET objects cannot be bound in XAML (although I don't see why you could write a minimal wrapper for them to which you could bind from XAML).

Strange that the WPF Team in making the WPF MVVM templates define the DataContext in code which very quickly makes it impracticable to edit your Views in Expression Blend, since your data doesn't show up in design mode which is often a significant part of the layout.

So I'm thinking there must be some advantage down the road to setting the DataContext in code instead of XAML, anyone know what it is?

Periderm answered 14/5, 2009 at 11:31 Comment(0)
B
16

You can (maybe in 2009 you couldn't) get the best of both worlds by using the d:DataContext attribute. You don't need any of that ViewModelLocator craziness if you're not ready for that yet :-)

First make sure that you have the following XML namespace defined in your root element:

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

Then you can add the following attribute to an element in your xaml:

d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type=vm:CustomerInsightViewModel}"

In your xaml codebehind :

    public CustomerInsightUserControl()
    {
        InitializeComponent();

        if (!DesignerProperties.IsInDesignTool)
        {
            DataContext = new CustomerInsightViewModel();
        }
    }

Then in your ViewModel:

    public CustomerInsightViewModel()
    {
        if (IsInDesignMode)
        {
            // Create design time data
            Customer = new Customer() {
                FirstName=... 
            }
        }
        else {
            // Create datacontext and load customers
        }
    }

Don't miss the IsDesignTimeCreatable=True or else Blend won't instantiate your class

Balbo answered 1/8, 2010 at 5:32 Comment(1)
If you get a compile time error starting "The property 'DataContext' must be in the default namespace...", the solution for this is at https://mcmap.net/q/117102/-setting-design-time-datacontext-on-a-window-is-giving-a-compiler-error/62278Reed
A
6

I don't like the idea of having Expression Blend try to instantiate my data objects.

I set the DataContext through code where I am able to use Dependency Injection to inject the proper objects, services, providers or what else I am using to find my code.

Allanadale answered 14/5, 2009 at 11:38 Comment(0)
M
1

Having it in codebehind makes it easy to inject the datacontext using unity.

Mallissa answered 14/5, 2009 at 11:33 Comment(2)
Is there a best-of-both-worlds solution to this? Does this mean that if you use Composite Application Library / Unity that you basically can cut and paste from Expression Blend or is there a simple way to e.g. have mock default DataContexts in XAML which designers can use in Blend?Periderm
see my answer on the DataobjectProvider. It could be used as a facade to delegate the instantiation and use something coming from DI.Cathycathyleen
C
1

There could be a kind of solution to this, using the DataObjectProvider to mask the fact that the data is instantiated outside of XAML.

It will state what the type of the DataContext is, which should be enough for Blend to pick up the properties.

I have not tried this yet, so take it with a grain of salt, but it is certainly worth investigating.

Cathycathyleen answered 14/5, 2009 at 12:0 Comment(0)
A
1

See Rob's article about design time data in Blend: http://www.robfe.com/2009/08/design-time-data-in-expression-blend-3/

Algoid answered 4/12, 2009 at 15:25 Comment(0)
S
1

It should also be possible to use ObjectDataProvider to establish an object factory using Unity or other IOCs as implied here...

http://social.msdn.microsoft.com/Forums/en/wpf/thread/1ff9e90e-302e-436e-bab3-ca4bad2b85af

in particular...

http://www.codeproject.com/Articles/43806/WPF-Ninject-Dojo-The-Data-Provider.aspx

Spikes answered 31/3, 2011 at 0:43 Comment(0)
S
0

In my experience, it is best to design an interface layout against at least a sample of the data it will present. To do otherwise is to be blind to cheap insights and expensive oversights.

Spikes answered 21/3, 2011 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.