Reputation: 99
I've read in other posts that in place of specifying the DataContext in code behind it can be specified in XAML.
I have an ObservableCollection declared and populated in the constructor of my main class where I also set the DataContext:
using System;
using System.Windows;
using System.Collections.ObjectModel;
namespace ItemsControlDemo
{
public partial class MainWindow : Window
{
public ObservableCollection<Person> PersonList { get; set; }
public MainWindow()
{
InitializeComponent();
PersonList = new ObservableCollection<Person>();
PersonList.Add(new Person(16, "Abraham", "Lincoln"));
PersonList.Add(new Person(32, "Franklin", "Roosevelt"));
PersonList.Add(new Person(35, "John", "Kennedy"));
PersonList.Add(new Person(2, "John", "Adams"));
PersonList.Add(new Person(1, "George", "Washington"));
PersonList.Add(new Person(7, "Andrew", "Jackson"));
DataContext = this;
}
private void Button_Add_Click(object sender, RoutedEventArgs e)
{
PersonList.Add(new Person(3, "Thomas", "Jefferson"));
}
private void Button_Remove_Click(object sender, RoutedEventArgs e)
{
PersonList.Remove(TheDataGrid.SelectedItem as Person);
}
}
public class Person
{
public Person() { }
public Person(int id, string firstName, string lastName)
{
ID = id;
FirstName = firstName;
LastName = lastName;
}
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
If I do this, all works well in my application.
However, if I remove "DataContext = this;" from the constructor and instead set the DataContext in the Window element of my application
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I get no data.
This is the XAML where I set the DataContext after I have removed it from code behind:
<Window x:Class="ItemsControlDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ItemsControlDemo"
Title="Items Control Demo" Height="350" Width="400"
WindowStartupLocation="CenterScreen"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0" Name="TheDataGrid" SelectedValuePath="ID"
AutoGenerateColumns="False"
AlternatingRowBackground="Bisque"
ItemsSource="{Binding PersonList}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID}"/>
<DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="1" Orientation="Horizontal"
HorizontalAlignment="Left" VerticalAlignment="Bottom">
<Button Content="Add Item" Margin="5" Click="Button_Add_Click"/>
<Button Content="Remove Item" Margin="5" Click="Button_Remove_Click"/>
</StackPanel>
</Grid>
</Window>
Any help in what I am doing incorrectly would be greatly appreciated.
Thanks!
Upvotes: 1
Views: 1184
Reputation: 4706
You need to setup your source before calling InitializeComponent
Edit: Actually you just need to instantiate it before InitializeComponent, since it's an ObservableCollection it implements INotifyCollectionChanged, so if you modify the collection, your grid will be updated with the changes.
public MainWindow()
{
PersonList = new ObservableCollection<Person>();
InitializeComponent();
PersonList.Add(new Person(16, "Abraham", "Lincoln"));
PersonList.Add(new Person(32, "Franklin", "Roosevelt"));
PersonList.Add(new Person(35, "John", "Kennedy"));
PersonList.Add(new Person(2, "John", "Adams"));
PersonList.Add(new Person(1, "George", "Washington"));
PersonList.Add(new Person(7, "Andrew", "Jackson"));
}
Upvotes: 3
Reputation: 6830
216's answer works. Alternatively, you can implement INotifyPropertyChanged
so the XAML is notified when you do set PersonList
.
ObservableCollection
only notifies when items in the collection change. If you want to notify when you assign a new value to the collection (e.g. PersonList = new ObservableCollection<Person>()
), you need to implement INotifyPropertyChanged
.
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Person> personList;
public ObservableCollection<Person> PersonList
{
get { return personList; }
set
{
if (value == personList)
return;
personList = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("PersonList"));
}
}
public MainWindow()
{
InitializeComponent();
PersonList = new ObservableCollection<Person>();
// etc.
}
}
Upvotes: 2