Reputation: 2013
I've wrote the following C# and XAML Code:
namespace ListViewExample1
{
public partial class MainWindow : Window
{
public ObservableCollection<MyColleague> myCollegues = new ObservableCollection<MyColleague>();
public MainWindow()
{
myCollegues.Add(new MyColleague() { Name = "Tim", Surname = "Meier" });
myCollegues.Add(new MyColleague() { Name = "Martin", Surname = "Hansen" });
myCollegues.Add(new MyColleague() { Name = "Oliver", Surname = "Drumm" });
InitializeComponent();
}
public ObservableCollection<MyColleague> MyColleagues
{
get { return this.myCollegues; }
}
}
public class MyColleague
{
public String Name { get; set; }
public String Surname { get; set; }
}
}
XAML-Code:
<Grid>
<ListView ItemsSource="{Binding}" DataContext="{Binding RelativeSource={RelativeSource ListViewExample1:MainWindow}, Path=myCollegues}">
<ListView.View >
<GridView >
<GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Surname" Width="150" DisplayMemberBinding="{Binding Surname}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
Now I need to set the datacontext, but at this point I have some irritations. Which DataContext-Syntax is right?
Upvotes: 2
Views: 15546
Reputation: 96770
There are dozens of ways to set DataContext
; no one is inherently right.
It's worth noting that there's no reason to set DataContext
on an items control at all if all you need is to bind one property (ItemsSource
, in this case). Setting DataContext
simplifies binding multiple properties, because all of the bindings use the same context.
If you want to do data binding without any code-behind (as you said in a comment), the example you've chosen isn't very good, since you're creating the object in code-behind. Try creating a class with a parameterless constructor, e.g.:
public class MyColleagueCollection : ObservableCollection<MyColleague>
{
public MyColleagueCollection()
{
Add(new MyColleague() { Name = "Tim", Surname = "Meier" });
Add(new MyColleague() { Name = "Martin", Surname = "Hansen" });
Add(new MyColleague() { Name = "Oliver", Surname = "Drumm" });
}
}
Then you can do:
<ListView>
<ListView.ItemsSource>
<local:MyColleagueCollection/>
</ListView.ItemsSource>
...
</ListView>
Or you could set the DataContext
, and set the ItemsSource
to "{Binding}"
. Or create the object in a resource dictionary, and bind using StaticResource
.
You could also create your collection as a property (not a field, as x0r correctly points out) of the Window
class and do this:
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"...
which now makes the Window
itself the data context object, allowing any element in the window to bind to its properties directly without using RelativeSource
.
Or (we're nowhere near done), you can give the window a name, and then bind to it by name:
<ListView ItemsSource=`{Binding ElementName=MyWindow, Path=MyCollection}"...
Let's not even get into using an ObjectDataProvider
.
What most people end up doing - this is as close to a "right" answer as you're going to find - is creating a view model class for the main window, instantiating it in the window's constructor, and setting the window's DataContext
to that object. From that point on, any view that the main window displays is bound to a property of that view model. See Josh Smith's article on the Model/View/ViewModel pattern for a really good worked example.
Binding and data contexts are incredibly versatile. This of course also means that there are a lot of things you can get wrong. It goes with the territory. Once you understand them, though, you rarely run into real problems.
Upvotes: 7
Reputation: 20764
Your binding to myCollegues
can't work, because you bind to a field. You have to bind to the property, which is MyColleagues
in your case.
The simplest solution to set your DataContext
would be in code-behind, assuming that MainWindow.xaml
contains the ListView
:
public MainWindow()
{
[...]
InitializeComponent();
DataContext = this;
}
Instead of keeping your data in code-behind, a better solution would be to use the MVVM approach. There you keep your data in a separate class, and then set the DataContext
to an instance of this class.
To bind in XAML use the following syntax:
<ListView ItemsSource="{Binding MyCollegues}"
DataContext="{Binding Path=., Mode=FindAncestor, RelativeSource={RelativeSource AncestorType={x:Type ListViewExample1:MainWindow}}}">
Upvotes: 0