How do I bind a lookup combobox? - wpf

My WPF4 combobox dropdown list is incorrectly displaying the class name of my EF4 entity. Here is the relevant XAML:
<Window.Resources>
<CollectionViewSource x:Key="myEntitiesViewSource"/>
</Window.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource myEntitiesViewSource}}" DisplayMemberPath="CategoryDescription" SelectedValuePath="CategoryID" />
Here is the code in my Window_Loaded event:
var categoryList = from p in _context.Categories
orderby p.CategoryNumber
select p;
System.Windows.Data.CollectionViewSource myEntitiesViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("myEntitiesViewSource")));
// Load data by setting the CollectionViewSource.Source property:
myEntitiesViewSource.Source = categoryList;
My database has a many to many relationship between Projects and Categories with a join table called ProjectCategories. The Categories entity was automagically created as a single entity to represent two database tables:
1) the lookup table of Categories containing an ID, CategoryDescription and CategoryNumber and
2) the join table ProjectCategories containing only two fields - the IDs from the tables Projects and Categories. The entity model lives in a separate project from my WPF window.
My goal is to allow the user to select a CategoryDescription from the dropdown list, then click an Add Category button to add the selected Category to a separate list of ProjectCategories. With the current code I see the correct CategoryDescription in the combobox text area but the dropdown list displays only the entity class name Categories (preceded by it's namespace) multiple times!
How do I make this simple lookup combobox bind correctly and display a list of CategoryDescriptions and a SelectedValue of CategoryID? Note: I'd accept a code only approach leaving out the CollectionViewSource in XAML if it's possible.
Thanks!

Nevermind. I asked this question and have answered it myself. There was nothing wrong with my code or XAML. The problem was caused by the use of a third party theme to style my controls. Once I removed the theme the combobox binding problem went away. For more details see this post.

What about something like this?
<ComboBox ItemsSource="{Binding Categories}"
SelectedItem="{Binding Category}" DisplayMemberPath="Description" />
Instead of using a Selected Value, I would store the whole object. The selected value approach is old ASP style for my taste.
SelectedItem="{Binding Category}" is your Category object. Basically it has stored the selected item of the ComboBox.
When the user clicks a button for example, you can fire a Command from the ViewModel and you will have the corresponding selected Category object.

Related

Access to name of an object in combobox in WPF

I have a ComboBox in WPF, and a table (Trainer) in my DataBase. They are linked together as following:
comboTrain.ItemsSource = (from t in ctx.Trainers select t).ToList<Trainer>();
Also, I bind it in xaml as following:
<ComboBox x:Name="comboTrain" ItemsSource="{Binding TrainerCollect}"
DisplayMemberPath="Name" SelectedValuePath="TrainerId"/>
So, when I run the application, I see the name of all trainers in ComboBox. Now, I want to show only the name of trainer who is selected in ComboBox.
How can I do that?
I found a solution for my question: with using "comboTrain.Text" I could get the selected item as a string.

DataGrid: Partial binding

Let me try and state the simplest version of the question:
Can I have an UNBOUND dropdown-type column in my BOUND DataGrid?
Here is an example if the above statement is too abstract to understand:
A DataGrid named dgStudents that is bound to a DataTable named dtStudents, showing a few of the columns of the table, say Name, Age and City, all being simple DataGridTextColumns. I want to add a 4th column to my grid named say FavSports that is a simple dropdown type column, bound to a static list of common sports. The most important thing here is that (unlike other 3 columns) this dropdown column DOES NOT have a corresponding column in the DataTable. It'll just be required for the life of the DataGrid, so I'm not storing it anywhere.
I have tried the following:
<DataGridComboBoxColumn ItemsSource="{StaticResource Sports}">
where Sports is an array defined right within XAML:
<x:Array x:Key="Sports" Type="sys:String">
<sys:String>Football</sys:String>
<sys:String>Hockey</sys:String>
<sys:String>Tennis</sys:String>
</x:Array>
Can't get this to work for the life of me. The dropdown does display and user can select a value out of it that does show after user moves to another cell, but that's about it. After user comes back to that cell, the drop-down appears empty and even if user then leaves the cell without clicking the dropdown, the previous value is gone.
If you just want to bind to your StaticResource, try this:
<DataGridComboBoxColumn ItemsSource="{Binding Source={StaticResource Sports}}">

Create a control after selecting Item from grid in MVVM

I have a collection of items in grid(of telerik) and after I select any item of collection of items ( I know how to notice changing of selected item) I need to create a control in the same user control which will display some property of selected item.
The problem is that depending of what type(the class of collection have a field SomeType) of selected item is, I need to add a specific class.
So for example if I had a collection of cars, and I selected car which was suv, than I would had to add SuvControl, and when I selected van, then I would had to add VanControl. Those controls are different because have different names of fields and would have different behaviors.
I'm using MVVM Light .
I couldn't find any good example so I'll reward even for a link to some example.
What I would do would be binding the SelectedItem [property of the ListBox to the view model
SelectedItem={Binding SelectedItem, Mode=TwoWay}
or you could do ElementName binding too - all this to get to the details view's viewmodel.
The details view would use a DataTemplateSelector and you would display your details view like this:
<Grid
x:Name="DetailsGrid">
<prismvm:DataTemplateSelector
Content={Binding SelectedItem}>
<prismvm:DataTemplateSelector.Resources>
<DataTemplate
x:Key="Type1ViewModel">
<views:Type1View/>
</DataTemplate>
<DataTemplate
x:Key="Type2ViewModel">
<views:Type2View/>
</DataTemplate>
</prismvm:DataTemplateSelector.Resources>
</prismvm:DataTemplateSelector>
</Grid>
As suggested the DataTemplateSelector is the right way to go in most cases, and certainly the cleanest.
An alternative when you have few different templates (2 or 3) if to put them all and bind their visibility to the item type property so only one is visible at a time. Again, this is nor the recommended technique but in simple cases it can bring you to the desired result quickly.

Entity Framework - Sorting Relationproperties

my question is, how do I sort related items of an entity.
In an invoice editing window, I have one ComboBox displaying all customers:
XAML:
<UserControl.Resources>
<CollectionViewSource x:Key="cvsCustomers"
d:DesignSource="{d:DesignInstance local:Customer, CreateList=True}" />
...
</UserControl.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource cvsCustomers}}" .../>
Code-behind:
Dim cvsCustomers As System.Windows.Data.CollectionViewSource
cvsCustomers = CType(Me.FindResource("cvsCustomers"), System.Windows.Data.CollectionViewSource)
Dim qryCustomers = _
From c In myEntities.Customers _
Order By c.CustomerCode
Select c
cvsCustomers.Source = qryCustomers
Now I have a 2nd ComboBox displaying all contact persons of the selected customer. This works fine, but the entries in this second ComboBox are unsorted / sorted by ID.
XAML:
<ComboBox ItemsSource="{Binding Path=myInvoice.Customer.Contacts}" .../>
;
How do I get the list on the 2nd ComboBox sorted?
King regards,
and thanks in advance for tips/suggestions,
Nico
I think there are two possible things.
When loading the data: It sounds like you are using the lazyloading feature of EF to load the Contacts related to the Customer. To sort Contacts, you would need to set what is sort option, were it's and when it's, but with the lazyloading these cannot be set. So you can use the Eagerly loading or the Explicitly loading to get the Contacts ordered. Please check to Using DbContext in EF 4.1 Part 6: Loading Related Entities, based on EF4.1. Something like this, the Explicitly loading case:
//Oh, I'm not familiar with VB.NET, so it's C# code
var customer; // it's assumed to be initialized.
context.Entry(customer).Collection(c => w.Contacts)
.Query().Orderby(c =>c.Name).Load();
Through CollectionView after loading the data unordered: you can let the CollectionView order the Contacts. Please check to CollectionViewSource Class(MSDN).

WPF Combobox behavior weird

I have 2 comboboxes which we will call cbo1 and cbo2. Now, there is a relationship between cbo1 and cbo2. when i select an item at cbo1, the cbo2 ItemsSource is updated (since it is bound to the SelectedItem) anyway, below is the sample XAML code for it.
<ComboBox x:Name="cbo1" Grid.Row="0" Grid.Column="1" Margin="5" SelectedItem="{Binding Path=Brand}"></ComboBox>
<ComboBox x:Name="cbo2" Grid.Row="1" Grid.Column="1" Margin="5" SelectedItem="{Binding Path=Model}" ItemsSource="{Binding ElementName=cbo1, Path=SelectedItem.Models}" DisplayMemberPath="Name"></ComboBox>
the objects used are Brand and Model. Brand has a property named Models which contain a collection of Model objects ( typeof IList ). So basically, a one-many relationship between the 2 classes.
By the way, those 2 classes are used in NHibernate. Now, when I run the app, cbo1 which contains a collection of Brand objects is loaded with the items first. When I select a Brand item, the cbo2 with the Model collection is populated. As you have noticed, both Comboboxes have SelectedItem property bound to the current object properties Brand and Model specifically. When I select a Model on the cbo2, it does not reflect to the current object's Model property. Anything i missed?
typo: the first combo is called cbo1, but the second combo is binding to cbxBrand; but since you say the Models do appear, I'm guessing this is OK in your actual source code, and you renamed it for the Question here?
Anyway, your code completely worked for me, I put a breakpoint on the setter of the Model property and it hit it no probs, so the only thing I can possibly guess at is the Window's DataContext maybe incorrect?
Can you post your code-behind (or ViewModel) ?

Resources