I am trying out WPF for the first time and I am struggling with how to bind controls to a class that is built up using composition of other objects. For example, If I have class Comp that is built up of two separate classes (note various elements left out for clarity):
class One {
int _first;
int _second;
}
class Two {
string _third;
string _fourth;
}
class Comp {
int _int1;
One _part1;
Two _part2;
}
Now I understand that I can easily bind _int1 using a "get" defined in Comp. But how do I bind to the elements _part1._first, _part1._second. Do I have expose "getters" for them at the class Comp level? or can I expose them within the composite classes and use a binding path that points to them? And how does this work with setting the properties?
Thus is this the pattern?
....
<TextBlock Name="txtBlock" Text="{Binding Path=Third}" />
....
class One {
int _first;
int _second;
}
class Two {
string _third;
string _fourth;
}
class Comp {
int _int1;
One _part1;
Two _part2;
int Int1 { get { return _int1; } set { _int1 = value; } }
int First { get { return _part1._first; } set { _part1._first = value; } }
int Second { get { return _part1._second; } set { _part1._second = value; } }
string Third { get { return _part2._third; } set { _part2._third = value; } }
string Fourth { get { return _part2.fourth; } set { _part2._fourth = value; } }
}
...
Comp oComp = new Comp();
txtBlock.DataContext = oComp;
...
Or is this the pattern? (where I am not sure what to put for the path)
....
<TextBlock Name="txtBlock" Text="{Binding Path=_part2.Third}" />
....
class One {
int _first;
int _second;
int First { get { return _first; } set { _first = value; } }
int Second { get { return _second; } set { _second = value; } }
}
class Two {
string _third;
string _fourth;
string Third { get { return _third; } set { _third = value; } }
string Fourth { get { return _fourth; } set { _fourth = value; } }
}
class Comp {
int _int1;
One _part1;
Two _part2;
int Int1 { get { return _int1; } }
}
...
Comp oComp = new Comp();
txtBlock.DataContext = oComp;
...
Or am I on on my way to reinvent M-V-VM (which I am slowly starting to comprehend)?
....
<TextBlock Name="txtBlock" Text="{Binding Path=Third}" />
....
class One {
int _first;
int _second;
}
class Two {
string _third;
string _fourth;
}
class Comp {
int _int1;
One _part1;
Two _part2;
}
class CompView {
Comp _comp;
CompView( Comp comp ) {
_comp = comp;
}
int Int1 { get { return _comp._int1; } set { _comp._int1 = value; } }
int First { get { return _comp._part1._first; } set { _comp._part1._first = value; } }
int Second { get { return _comp._part1._second; } set { _comp._part1._second = value; } }
string Third { get { return _comp._part2._third; } set { _comp._part2._third = value; } }
string Fourth { get { return _comp._part2.fourth; } set { _comp._part2._fourth = value; } }
}
...
Comp oComp = new Comp();
CompView oCompView = new CompView( oComp );
txtBlock.DataContext = oCompView;
...
So how should I do things? If it is the first or the third pattern, then it seems that I have take all of my lovely (disparate) hierarchal data and pound it down to a flat configuration so I can bind it to the UI elements. Is this how it has to happen, or is there a better way (second pattern??)
Edit
I left out of the question that I really want two way binding. So the property accessors really should have get and set.
Edit
Updated my pseudo code to show setters as well as getters
Edit
I followed through the pattern provided by Mark and Julien and implemented setters and was happy with the result. For some reason I convinced myself that the setting of a property would not follow all the way down to the final entity.
I think you always have to bind to a property, so your classes should be:
Then, you should be able to bind to anything yo want:
Data Binding works through properties, so you won't use any of the member variables in your Binding, eg:
you'll use First and not _first for the binding. Normally I've seen each class provide it's own properties to bind to, in which case you could modify your code to:
Note that I made the properties public, while keeping the fields defaulted to private. If you assign the DataContext of a parent control to an instance of Comp:
You can then bind to the pieces in xaml as follows:
here you'll see the StackPanel is given a Comp as the DataContext (and therefore all of it's children also have that DataContext unless another one is specified), and the text is bound to it's member classes.
EDIT: I also added in setters as well as implemented INotifyPropertyChanged which is a vital component to databinding. With this implemented, you'll be able to bind your data to multiple controls and see the data update in all controls when updated. You'll need to add: using System.ComponentModel;