views:

447

answers:

2

Question: How do you set the binding for a ComboBox's Selected items to one property and the items list to a different property?


Info:

I have an inventory program I'm working on for my company which is aimed mostly at the people who receive shipments as they come in. I have things set up so that there is a list of shipments on one side of the screen. when they select one of these all the information on the shipment is displayed so it can be edited. one bit of information is the person who received the shipment. I want it so that when they click the shipment, obviously the user who received the shipment is the one who pops up in the combo box. but i want the combo box to contain the list of all the other users.

This wouldn't be to hard if it weren't for the fact that I'm pulling the list of users from a database. the list box has a data template for pulling the proper information out of the list of user data types. what I've tried so far is to have a collection view in the viewmodel that the combo box binds to for its list, then a seperate property which is a single user instance that comes with the shipment data type.

I'm programing in Visual Basic and XAML according to the M-V-VM programing model.

+1  A: 

There is nothing wrong with your approach. The ViewModel can expose a collection of types from the db and a separate property bound to the selected item, something like:

public ObservableCollection<Shipment> AllShipments { get; private set; }
public Shipment SelectedShipment { get; set; }

// Constructor
public MyViewModel()
{
    AllShipments = ReadFromDb();
}

In terms of the combobox being empty

  • Have a look in the output window in VS when you start your app - is there a line complaining about a Binding failing?
  • Double-check the spellings of your properties against your xaml Binding
  • Put a breakpoint on the AllShipments getter to make sure it is not null when the View instantiates the binding. If you read the db in the VM's constructor (as above) then this will be OK.

Also - if you want the combo-box to display the User from the shipment object, then remember to ensure your VM (or its base) implements INotifyPropertyChanged, and raises a PropertyChanged event in the SelectedShipment setter - this will propagate the change through to the View via the DataBinding...

hope this helps :)

IanR
turns out the reason why it wasn't populating was i missed a .ToList after my LINQ statement. So that works fine and dandy now. But I'm still not getting my shipment's user to bind properly. I have INotify implemented, but it still doesn't work. any further suggestions?
Narcolapser
I wrote a short series of blogs on how to create a *real simple* master-detail control at http://ianrandallonwpf.wordpress.com. It uses a ListBox, but you can easily swap it out with a ComboBox... HTH :)
IanR
I'm already doing that. My code is set up such that I have a list box on the left side of the screen. You select Shipment, then a content presenter on the right side displays the related data. Inside that content presenter is my trouble some combobox. The issue seems to lie in the fact that it is the detail and not the master. The combo box is bound to a list of Users like i want, but i want the selected user to be the one that the program loads from the db.
Narcolapser
It's not the answer I was looking for, but it's close enough to help anyone else who stumbles across this thread i hope. I ended up just passing the GUID to a converter which queried the db for the name associated with that GUID and displayed that. Thanks for your help anyway.
Narcolapser
A: 

I'll be answering this question assuming you're using Linq-to-SQL:

This is a common PITA problem, where the User property in your Shipment object contains a reference to a User object that is different from the User object from the query that populated the ComboBox, even though they represent the same record.

To overcome this, you might want to bind the users ComboBox to a list of users that is retrieved from the same DataContext as the list of Shipments.

Example:

class ViewModel
{
    public List<User> Users { get; set; }
    public List<Shipment> Shipments { get; set; }
    public Shipment SelectedShipment { get; set; }

    public void ReadShipments()
    {
        using (var dc = new MyDataContext())
        {
            DataLoadOptions dlo = new DataLoadOptions();
            dlo.LoadWith<Shipment>(x => x.User);
            dc.LoadOptions = dlo;
            Shipments = dc.Shipments.ToList();
            Users = dc.Users.ToList();
        }
    }
}
Aviad P.
Well turns out the box not populating was an id10t error. I forgot .ToList at the end of my LINQ statement... \nanyway, the list box populates, but i still can't set the selected user to the one in the shipment. i tried using my code translator on the C# you gave me, and it didn't make any sense in VB. I have the data context dimmed up at the beginning of the class, so it is the same context used for both. But I don't see how exactly that makes a difference. \n good guess on me using LINQ.
Narcolapser
Are you populating the combo with the same datacontext that you are querying your shipments by?
Aviad P.
On closer examination, no. I'm loading the users from inside the shipmentVM. This is the method i used for the pallets on the shipment, it worked fine, so i was recycling. should I have the users loaded and pass a reference to it by the AllShipmentsVM?
Narcolapser
I have a feeling you are keeping your `DataContext` alive for far more than is considered good practice, and that's going to get you into trouble as you add more and more views to your application (from experience :) ) - Anyway, whatever you do, you need to make sure the `ComboBox` `ItemsSource` is from the same `DataContext` that the shipment is loaded.
Aviad P.
I'm trying to get your dlo stuff working in basic. and there are some things i'm having issues translating. where does thatx => x.User come into play?
Narcolapser
So I've gotten user combo box to populate, where I'm having trouble now is in getting it to it to bind to the current object. I need the combo box to show the current shipment's user and when the person enterying the shipment changes the user, the new one is what is saved with this shipment to the database. if i can get that working, all is well.
Narcolapser