简体   繁体   中英

Binding a ComboBox to part of an ObservableCollection

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 (eg 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.

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM