What is the advantage of setting DataContext in code instead of XAML?
Solution 1
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
Solution 2
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.
Solution 3
See Rob's article about design time data in Blend: http://www.robfe.com/2009/08/design-time-data-in-expression-blend-3/
Solution 4
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
Solution 5
Having it in codebehind makes it easy to inject the datacontext using unity.
Angry Dan
web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info
Updated on April 22, 2020Comments
-
Angry Dan about 4 years
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?
-
Angry Dan about 15 yearsIs 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?
-
Denis Troller about 15 yearssee my answer on the DataobjectProvider. It could be used as a facade to delegate the instantiation and use something coming from DI.
-
Brian Hinchey almost 12 yearsIf you get a compile time error starting "The property 'DataContext' must be in the default namespace...", the solution for this is at stackoverflow.com/q/8303803/62278