views:

27

answers:

2

Hi,

I have a list box containing many items and I have a combobox in C# WPF.

I would like to bind the itemsource of the combobox to that of the listbox but I want to filter out some of the items (it's an xml datasource, I want to filter by the contents of a certain element of the item element). Example item:

    <Item>
<itemtype>A</itemtype>
<itemname>Name</itemname>
</item>

    <Item>
<itemtype>B</itemtype>
<itemname>Name</itemname>
</item>

I thought of manually adding an item to the combobox when adding an item to the listbox but then the 'name' value of the item is not updated when it is changed in the listbox.

What is a good way to do this? Let's say I only want to show all item names with itemtype B. Can it be done in wpf binding or do I have to do some code behind?

+1  A: 

The problem with Binding in this case, is that its only set once. So if you bind it, the sources are synchron. You could use a converter for the binding, which filters the items you not like to bind. Another way would be to use WPF's wonderful CollectionViewSource.

You can add Groupings/Sortings and a Filter to a CollectionViewSource on any kind of ItemsSource. Use the ListCollectionView for example.

ListCollectionView view = 
   (ListCollectionView)CollectionViewSource.GetDefaultView(yourEnumerableSource);
JanW
so is 'yourEnumerableSource' a reference to the listbox or to the datasource? And it is the view updated when a change is made to the datsource?
internetmw
see second post
JanW
+1  A: 

It's a reference to the datasource, e.g. to a collection in your viewmodel if you use MVC pattern. The amazing thing is, that it is so simple in usage. The view is updated an has it's own refresh handling. I'll make a little example:

In WPF:

<ListBox ItemsSource={Binding Path=MySource} ItemTemplate="{StaticResource myItemTemplate}" />

The code logic:

public class Item
{
    public string Name { get; set; }
    public string Type { get; set; }
}

public class MyViewModel
{
    public ObservableCollection<Item> MySource { get; set; }

    public MyViewModel()
    {
        this.MySource = new ObservableCollection<Item>();
        this.MySource.Add(new Item() { Name = "Item4", Type = "C" });
        this.MySource.Add(new Item() { Name = "Item1", Type = "A" });
        this.MySource.Add(new Item() { Name = "Item2", Type = "B" });
        this.MySource.Add(new Item() { Name = "Item3", Type = "A" });

        // get the viewsource

        ListCollectionView view = (ListCollectionView)CollectionViewSource
            .GetDefaultView(this.MySource);

        // first of all sort by type ascending, and then by name descending
        view.SortDescriptions.Add(new SortDescription("Type", ListSortDirection.Ascending));
        view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));

        // now i like to group the items by type
        view.GroupDescriptions.Add(new PropertyGroupDescription("Type"));

        // and finally i want to filter all items, which are of type C
        // this is done with a Predicate<object>. True means, the item will
        // be shown, false means not
        view.Filter = (item) =>
            {
                Item i = item as Item;
                if (i.Type != "C")
                    return true;
                else
                    return false;
            };


        // if you need a refreshment of the view, because of some items were not updated
        view.Refresh();

        // if you want to edit a single item or more items and dont want to refresh,
        // until all your edits are done you can use the Edit pattern of the view

        Item itemToEdit = this.MySource.First();
        view.EditItem(itemToEdit);
        itemToEdit.Name = "Wonderfull item";

        view.CommitEdit();

        // of course Refresh/Edit only makes sense in methods/callbacks/setters not
        // in this constructor
    }

}

Interesting is, that this pattern directly affects the listbox in the gui. If you add the grouping / sorting, this will affect the listbox's display behavior, even if the itemssource is only bound to the viewmodel.

JanW
Thanks for the detailed explanation. So how do I set my current datasource as the observablecollection? So according to your explanation I filter that collection. Do I bind the collection to my combobox in the code or in the xaml?
internetmw