How to define DataContext in XAML using StaticResource
Asked Answered
D

3

7

I want to declare a DataContext through a static resource in XAML as a binding for the Customers in the Northwind database. I can do this easily in code (C#) but want to learn how to do in XAML. I have tried all of the examples I can find but none of them work for me. I believe the issue is in the two XAML lines of code I have labeled [Option1] and [Option2]. Can you clarify what the syntax for this really should be?

C#

namespace DataGridEF
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            bModel1 bNorthWind = new bModel1();
            //this.DataContext = bNorthWind;
            bNorthWind.GetCustomers();
        }
    }
}

namespace DataGridEF
{
    public class bModel1
    {
        List<Customer> _Customers;
        public List<Customer> Customers
        {
            get { return _Customers; }
            set { _Customers = value; }
        }

        public void GetCustomers()
        {
            NorthwindEntities NorthWind = new NorthwindEntities();
            var CustomerQ = from cust in NorthWind.Customers select cust;
            _Customers = CustomerQ.ToList();
        }

    }
}

XAML

 <Window x:Class="DataGridEF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:vm="clr-namespace:DataGridEF">

<Window.Resources>
    <vm:bModel1 x:Key="TheViewModel" />
</Window.Resources>

<Grid>
    <DataGrid AutoGenerateColumns="False" Height="195" 
              HorizontalAlignment="Left" Margin="20,89,0,0" 
              Name="dataGrid1" ItemsSource="{Binding Path=Customers}" 
              [option1]DataContext="{StaticResource TheViewModel}"
              [option2]DataContext=
                  "{Binding Path=., Source={StaticResource TheViewModel}}"
              VerticalAlignment="Top" Width="471" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Path=ContactName}" />
            <DataGridTextColumn Header="Address" Binding="{Binding Path=Address}" />
            <DataGridTextColumn Header="City" Binding="{Binding Path=City}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>
</Window>
Decentralization answered 16/8, 2010 at 19:25 Comment(1)
Once you've set the Window.DataContext in XAML (<Window.DataContext><vm:bModel1 /></Window.DataContext>) you shouldn't have to set the DataContext on the data grid at all.Greenstone
O
9

If to avoid complicating the question with Entities Framework and MSSQL NorthWind database, then the good illustration is provided in Example2 sample code of codeproject "WPF/MVVM Quick Start Tutorial"

For your XAML you should change the beginning of it to:

<Window x:Class="DataGridEF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:vm="clr-namespace:DataGridEF">

<Window.DataContext>
        <vm:bNorthWind />
    </Window.DataContext>
<Grid>
<!---Couldnt check your code due to dependencies on 
     EF and MSSQL NorthWind database

     See the reference for working illustration sample:
 http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

-->
</Grid>
</Window>

Another variation of this approach can be seen in "What is the advantage of setting DataContext in code instead of XAML?", the part:

    <StackPanel.DataContext>
        <local:CustomerViewModel />
    </StackPanel.DataContext>   

Migrating DataContext definition from codebehind to XAML is unrelated to the usage of either StaticResource or DynamicResource. See: What's the difference between StaticResource and DynamicResource in WPF? probably better addressed in codeproject WPF: StaticResource vs. DynamicResource

Related, helpful and further reading:

Observant answered 22/4, 2013 at 2:48 Comment(0)
H
1

I prefer to set the key as a static string - WPF has enough magic strings without cornering yourself into a refactoring corner if you can easily avoid it.

in App.xaml

xmlns:viewModels="clr-namespace:MyAppNamespace.ViewModels"
xmlns:local="clr-namespace:tvCADdesktop"
x:Name="App"
...
<viewModels:ApplicationViewModel x:Key= "{x:Static local:App.MainVmResourceKey}"/>

in App.xaml.cs

public static readonly string MainVmResourceKey = "MainVm";

in my various Control.xaml

<UserControl.DataContext>
    <Binding>
        <Binding.Source>
            <StaticResource ResourceKey="{x:Static app:App.MainVmResourceKey}" />
        </Binding.Source>
    </Binding>
</UserControl.DataContext>

note the UserControl part is whatever type you want to apply the ViewModel to.

Horseman answered 24/4, 2016 at 9:49 Comment(0)
P
0
<Window xmlns:vm="clr-namespace:YourApplication.ViewModels">

    <Window.Resources>
        <vm:MainWindowViewModel x:Key="MWVM" />
    </Window.Resources>

    <Window.DataContext>
        <StaticResource ResourceKey="MWVM" />
    </Window.DataContext>

</Window>

Edit:

Unlike the other answers, this one attempts to simply show you exactly how to define a ViewModel as a StaticResource in XAML and use that resource for a DataContext.

Puett answered 4/12, 2019 at 21:35 Comment(4)
Is there any benefit to using a static resource vs. setting Window.DataContext directly? If not, then this answer suggests setting it directly.Greenstone
@ZevSpitz - Yes, there is a benefit when you are binding a property from your main ViewModel (DataContext of Window), for example, to a UserControl that has its own ViewModel. If you try to bind a property from the main ViewModel to the UserControl in XAML it won't work and you'll even get a warning. So what you have to do is reference the main ViewModel. Like this: <controls:MyUserControl Title="{Binding Path=Title, Source={StaticResource ResourceKey=MWVM}}" />Puett
Not enough of a justification to my mind. If you need to worry about that case, you can use {Binding Path=DataContext.Title, RelativeSource={RelativeSource AncestorType=Window}}.Greenstone
@ZevSpitz That certainly works too. It just requires longer bindings and gives less flexibility, if you need that sort of thing.Puett

© 2022 - 2024 — McMap. All rights reserved.