Reputation:
I have a WPF application in C# where I have an object of class MyCollection
that extends ObservableCollection<MyType>
which holds items for the purpose of binding them to several ComboBoxes.
However, every ComboBox must display a subset of this collection (based on a certain property of its elements), and that may change based on user input.
How can I obtain this behavior keeping every subset updated with data from the original collection? Is there some well known design pattern for this scenario?
EDIT: Since my formulation of this question is easily misunderstood, here's an example.
I have an ObservableCollection<Person>
object, where the class Person
has an Age
and Name
properties.
I have three combo boxes, the first two must display the Name
of Person
objects with an odd Age
, while the third must it of those with an even Age
. Their roles might change at runtime (e.g. first and last has to display odd ages, the second even ages)
If Person
objects are added to or deleted from the collection, changes must be reflected on the corresponding ComboBoxes.
Name
and Age
properties may be considered constant.
Upvotes: 4
Views: 901
Reputation: 1156
If I understand your question correctly, you need some sort of filtering mechanism.
Take a look at an ICollectionView
interface and its implementations such as CollectionViewSource
that might help you to achieve this.
You need to handle the Filter
event that implements the filtering logic.
Here is the class at MSDN (http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource(v=vs.110).aspx)
An example:
Container class:
public string Name { get; set; }
public string Capital { get; set; }
public Country(string name, string capital) {
this.Name = name;
this.Capital = capital;
}
Model class:
private ObservableCollection<Country> _countries;
private ICollectionView _european;
private ICollectionView _american;
public ObservableCollection<Country> Countries {
get {
if (_countries == null) {
_countries = new ObservableCollection<Country>();
}
return _countries;
}
}
public ICollectionView European {
get {
if (_european == null) {
_european = new CollectionViewSource {
Source = this.Countries
}.View;
_european.Filter += (e) => {
Country c = e as Country;
if (c.Name == "UK" || c.Name == "Ireland" || c.Name == "France") {
return true;
}
return false;
};
}
return _european;
}
}
public ICollectionView American {
get {
if (_american == null) {
_american = new CollectionViewSource {
Source = this.Countries
}.View;
_american.Filter += (e) => {
Country c = e as Country;
if (c.Name == "USA" || c.Name == "Canada" || c.Name == "Mexico") {
return true;
}
return false;
};
}
return _american;
}
}
Initialization code:
private Model _model;
public Model Model {
get {
if (_model == null) {
_model = new Model();
}
return _model;
}
}
public MainWindow() {
InitializeComponent();
this.DataContext = this.Model;
this.Model.Countries.Add(new Country("UK", "London"));
this.Model.Countries.Add(new Country("Ireland", "Dublin"));
this.Model.Countries.Add(new Country("France", "Paris"));
this.Model.Countries.Add(new Country("USA", "Washington D. C."));
this.Model.Countries.Add(new Country("Mexico", "Mexico City"));
this.Model.Countries.Add(new Country("Canada", "Ottawa"));
}
XAML:
<StackPanel>
<ComboBox
ItemsSource='{Binding Path=European}'>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation='Horizontal'>
<TextBlock
Text='{Binding Path=Name}' />
<TextBlock
Text=', ' />
<TextBlock
Text='{Binding Path=Capital}' />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox
ItemsSource='{Binding Path=American}'>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel
Orientation='Horizontal'>
<TextBlock
Text='{Binding Path=Name}' />
<TextBlock
Text=', ' />
<TextBlock
Text='{Binding Path=Capital}' />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
Upvotes: 2