none
How to set Window.DataContext declaratively in XAML

    Question

  • Hi,

    In my window, I declare and populate an ObservableCollection<Person> _persons;  Then I assign it as the DataContext of the window like this: this.DataContext = _persons;

    I have a listbox in the window and in XAML I bind it to the collection like below which works well.  My question is how do I declaratively set the datacontext in XAML, instead of codebehind?  I've played around with <Window.DataContext/> but could get it right. 

            <ListBox
                     ItemsSource="{Binding}"
                     DisplayMemberPath="FullName">
            </ListBox>
    

     

    Tuesday, March 23, 2010 3:35 PM

Answers

  • Hi there,

    there's several possible approaches. One would be to set the DataContext of your window using DataContext="{Binding RelativeSource={RelativeSource Self}}" . After you've done that, the DataContext of your window would point to its code behind. From there, you'll need a property to expose your _persons collection. Assuming the property you create was named Persons , you would then bind your ListBox via ItemsSource="{Binding Persons}" .

    As an alternative, you could skip binding your window and bind the ListBox directly. For that to happen, you could do so with ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Persons}" .

    Note that defining a property for your _persons collection is mandatory - you can't bind to local members; that's probably your main issue.


    Cheers,
    Olaf
    http://blogs.intuidev.com
    • Marked as answer by stratoblue Tuesday, March 23, 2010 7:16 PM
    Tuesday, March 23, 2010 3:56 PM

All replies

  • Hi there,

    there's several possible approaches. One would be to set the DataContext of your window using DataContext="{Binding RelativeSource={RelativeSource Self}}" . After you've done that, the DataContext of your window would point to its code behind. From there, you'll need a property to expose your _persons collection. Assuming the property you create was named Persons , you would then bind your ListBox via ItemsSource="{Binding Persons}" .

    As an alternative, you could skip binding your window and bind the ListBox directly. For that to happen, you could do so with ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Persons}" .

    Note that defining a property for your _persons collection is mandatory - you can't bind to local members; that's probably your main issue.


    Cheers,
    Olaf
    http://blogs.intuidev.com
    • Marked as answer by stratoblue Tuesday, March 23, 2010 7:16 PM
    Tuesday, March 23, 2010 3:56 PM
  • Perhaps you can create a wraper for the collection of person in code, and load the collection of person object in Window.Resources with a key in xaml.

    Example:

    <Window x:Class="SetDataContextInXAML.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:SetDataContextInXAML"
        Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <local:People x:Key="people"/>
        </Window.Resources>
        <StackPanel>
            <ListBox DataContext="{StaticResource people}" ItemsSource="{Binding}" DisplayMemberPath="Name"/>
        </StackPanel>
    </Window>

    Code:

    using System.Collections.ObjectModel;
    using System.Windows;

    namespace SetDataContextInXAML
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
        }
        public class People : ObservableCollection<Person>
        {
            public People()
            {
                Add(new Person { Name = "Tom" });
                Add(new Person { Name = "Ken" });
                Add(new Person { Name = "Jen" });
            }
        }
        public class Person
        {
            public string Name { set; get; }
        }
    }

    Hope it helps.


    William
    Tuesday, March 23, 2010 3:58 PM
  • Hi Olaf,

    Thanks for your reply.  "RelativeSource" was what I was looking for.  Your first solution works as long as I make sure the Persons collection is already populated before the window's InitializeComponent() is called.  I was getting an error when I first tried your second solution.  But as soon I added a reference to the namespace of my window, the error wenet away.  And it even worked even if I populate persons after InitializeComponent() is called.

    I checked your blog site and found some interesting stuff there.  Count on me to visit one of these days.  Thanks again.

     

    Tuesday, March 23, 2010 7:16 PM
  • William,

    Although your solution is not exactly what I was looking for, I like it a lot.  It opened me to a big spectrum of possible usage when I move forward to actual production work.  Thanks.

    Tuesday, March 23, 2010 7:46 PM
  • If you want to use a ViewModel class instead of code behind, you can declare your DataContext like this:

    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>

    Obviously, you would assign the namespace of the ViewModel to 'local'.

    Greg

    Thursday, March 22, 2012 9:00 PM
  • This has been awhile but the answers are incomplete:

    When the namespace is in a different assembly, you have to specify it using the assembly feature of the namespace value, despite having referenced the assembly in the containing project. This assembly information is not reliably added by IntelliSense when adding the reference, for some reason.

    For example:

    <Window x:Class="Project1.MainWindow"
            xmlns="http://schemas.microsof...."
            ...
            xmlns:vm="clr-namespace:ClassLibrary1;assembly=ClassLibrary1"
            ...
            >
    
        <Window.DataContext>
            <vm:Class1 />
        </Window.DataContext>
    
        <Grid />
    </Window>



    • Edited by G1 Tuesday, March 19, 2013 10:10 PM incomplete
    Tuesday, March 19, 2013 10:08 PM