What is normally bound to a wpf combobox - wpf

I want to bind something to a combobox that will display something different than it's value.
What would be the suggested/most common data container to link the combobox to? Would it be a custom type and then do a list of that type? A data table? I am using vb.net and wpf. The list would be something like:
dog,1
cat,2
bird,3
fish,4
The combobox would display the animal name and the value would be the number. The data to populate the combobox will come from a MYSql database.

Set the DisplayMemberPath on your Combobox to the property of the underlying object you want to
display.
So assuming you have an object like this:
Public Class Animal
{
string Name {get;set;}
int Number {get;set;}
}
You would set your DisplayMemberPath to Name.
Else check out this link for a more complete answer:
Binding WPF ComboBox to a Custom List

You can populate with anything you want, you can also display multiple items like so
<ComboBox ItemsSource{Binding ItemList}>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding AnimalName}" />
<Checkbox IsChecked={Binding SelectAnimal}" Content="{Binding Age}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The Select animal is just so you can get an idea of doing a template

Related

How does wpf/databinding resolve this ambiguity?

<StackPanel DataContext="{StaticResource Employees1}">
<ListBox ItemsSource="{Binding}" DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True"/>
<Label Content="{Binding Path=Count}"/>
<Label Content="{Binding Path=Name}"/>
</StackPanel>
How does the binding for the labels get resolved? How is it decided that the content of the second label is bound to Employees1.Count (and not to Employee.Count), while the first label is bound to
Employee.Name and synchonized with the listbox selection? Also, what if I would like to bind the first label to Employee.Count instead?
(Employee has properties Name (and possibly Count), Employees1 is an ObservableCollection of type Employee).
EDIT: So, the question here is WHY the first label displays the number of employees in the ObservableCollection, while the second label displays the name of a specific employee in the collection, the one that is currently selected in the ListBox. Apparently, the first label binds to the entire collection, and the second label to a specific employee in the collection. But why, and how to control this behavior.
From MSDN Data Binding Overview, Binding To Collections, section "Current Item Pointer":
Because WPF binds to a collection only by using a view (either a view
you specify, or the collection's default view), all bindings to
collections have a current item pointer.
and section "Master-Detail Binding Scenario":
This works because when a singleton object (the ContentControl in this
case) is bound to a collection view, it automatically binds to the
CurrentItem of the view.
In your example, the second Label automatically binds to the current item of the default view of the Employees1 collection. The first Label would also bind like this, but since the item object does not have a Count property it apparently falls back to a binding to the Count property of the collection itself. However i don't know if the latter behaviour is documented somewhere.
As Blam says - the labels have no relationship to the listbox - I think what you're trying to do here is bind an observableCollection of Employees with properties Count and Name to the listbox..
To do this you'll need an ItemsTemplate in the listbox
<ListBox ItemSource={Binding Employees1}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Count}" />
<Label Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Let me try and answer the questions.
An ObservableCollection has a property Count.
As for getting a single property on the second label it is making some assumptions.
You might not get the same behavior in other version of .NET.
Should not bind a control that displays a single value to a collection.
If you want the selected item from the ListBox see this link
enter link description here

Bind a ComboBox to two DataContexts

I have a ComboBox in my wpf application.
It's ItemsSource is binded to some table in my DataSet.
I need the text property to be binded to another's object property . I doesn't work because the ComboBox doesn't want to get two DataContexts. How can I solve this problem?
<StackPanel Width="Auto" Height="Auto" MinWidth="296" Orientation="Vertical" x:Name="MyStackPanel">
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding Path=MyProperty} />
</StackPanel>
In the code behind :
MyComboBox.DataContext = MyDataSet.Tables[MyTable];
MyStackPanel.DataContext = MyObject;
I want the ComboBox to show items from one DataContext but to show the text from another DataContext. How can I do it?
Don't use DataContext. Set the Source property of your bindings in XAML or create the bindings in code and set the Source property there.
Why are you assigning something to the datacontext of the stackpanel? From the looks of it, its not used.
Your code should work if MyDataSet.Tables[MyTable] returns an enumeration and contains a property called MyProperty.
What do you mean when you say that the combobox "doesn't want to get two DataContexts"?
Look into the properties IsEditable and IsReadOnly of the combobox.
Something like
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding ElementName=MyStackPanel Path=DataContext.MyProperty} />

Bind datagrid to one ViewModel, column / combobox to another

I a have a View Players, the datacontext is set to a ObservableCollection Players from the ViewModel MainPlayerViewModel.
In the View I have a datagrid with columns TeamId, Name and Position.
I want to bind the TeamId column with a combobox to a list of available teams from the MainTeamViewModel which has a collection property Teams but of course I want the MainPlayerViewModel to be updated whenever I update the team for a player.
I hope you can follow me here..
This is my xaml:
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}"
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Teams,
Mode=TwoWay}" SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
When I edit the cell it shows the list of available teams but the selectedvalue I pick from the list doesn't turn up in the TeamId column
How do I pull this off?
Kind regards,
Mike
UPDATE:
Despite the help I received I didn't get it to work binding one View to 2 different Viewmodels.
Guess the solution offered is long above my head..
I couldn't set the datacontext of the datagrid to MainTeam because it has an ItemsSource of players and a selecteditem bound twoway to selectedplayer.
Anyway I decided to keep it 1 View / 1 ViewModel and created a public property on my PlayerViewModel named teamsVM:
public MainTeamViewModel teamsVM
{
get
{
return ViewModelLocator.Container.Resolve<MainTeamViewModel>();
}
}
Now I can set the Itemsource to this new property and my player row get's updated when I change teams:
<DataTemplate>
<ComboBox
Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding teamsVM.Teams,
Mode=TwoWay}" SelectedValue="{Binding Model.teamid, Mode=TwoWay}"
DisplayMemberPath="Model.teamid" SelectedValuePath="Model.teamid"/>
</DataTemplate>
Regards,
Mike
I find two things wrong with this code.
You are missing the SelectedValuePath for the ComboBox. Even though you bind all teams to it, the selected item's id is null because the SelectedValuePath is missing.
You also have a DataContext and an ItemsSource. Use only the ItemsSource for the teams you want to display, and the SelectedValue to be bound to the player's teamId, unless your view model has a "Teams" property and a "Player" property, in which case the DataContext may be used. (Id set the DataContext in code though...)
So yo will end up with something like this:
ItemsSource="{Binding Teams, Mode=TwoWay}" //Bind to all teams.
SelectedValue="{Binding Player, Path=TeamId, Mode=TwoWay}" //Bind to the teamId of the player.
DisplayMemberPath="TeamName" //that's the Name of each team.
SelectedValuePath="TeamId" //that's the Id of the team.
Two problems here:
First, as #bleepzer noted you did not specify the value/display paths in your combo box.
Second, you trying to access a property in the data context that is outside your grid (i.e. the main view model's data context) from within a data template. In silverlight 4 there is no relative source binding (something you would use in SL 5 or WPF), so you will have to use element binding to archive what you want.
Here is an example based on your code. It is not complete as it leaves out some of the DataGrid elements needed, but it shows the concept:
<data:DataGrid x:Name="myDataGrid"
DataContext="{Binding MainTeam, Mode=OneWay, Source={StaticResource Locator}}" >
<!-- additional stuff needed here -->
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Height="23" HorizontalAlignment="Left"
Name="cmbTeams" VerticalAlignment="Top" Width="100"
ItemsSource="{Binding ElementName=myDataGrid, Path=DataContext.Teams}"
SelectedValuePath="TeamId"
DisplayMemberPath="TeamName"
SelectedValue="{Binding Path=Model.teamid, Mode=TwoWay}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
<!-- additional stuff needed here -->
<data:DataGrid>
And here is the description:
Add a name to your data grid.
Make sure the data grid has the right data context, either by setting it explicitly as in the sample, or inheriting it from the parent hierarchy.
Modify your ComboBox's ItemsSource property to point to the data grid using the element name you specified earlier. As you are now on the element and not on the data context you have to use DataContex.Teams to access the Teams property on the data context of your grid. The ItemsSource does not need two-way-binding as the view does not write anything back to your view model.
Specify the SelectedValuePath and DisplayMemberPath properties.
Finally, bind the SelectedValue property of the combo box to your rows model TeamId property using two-way-binding - needed now as the view should update the model's value. Important: the SelectedValue property of the combo box has to be bound after the ItemsSource to prevent some problems with the combo box.

How to set TextSearch.Text for a combobox whose TextBlock uses converter?

In the below code, Combobox is wired to NameInfo object along with a converter.NameInfoConverter returns a format in which items in combobox are shown in a particular format (for eg: LastName, FirstName (Badge#) )
Now, when I set TextSearch.Text="{Binding NameInfo, Converter={StaticResource NameInfoConverter}, ConverterParameter=true}" on combobox; TextSearch doesn't work. When I set TextSearch.TextPath="Name", search itself works but doesnot get the correct format displayed in the selectionbox of combobox.
Any Ideas?
<StackPanel>
<ComboBox x:Name:"cmbName">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name,
Converter={StaticResource NameInfoConverter}, ConverterParameter=true}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
You've probably hit a limitation in the API. I suggest you take an alternative route and bind directly to a property that is correctly formatted for your textblock.
If this is a serious app, you may want to look into using the MVVM pattern and place your converted/formatted property in the viewmodel. Otherwise, just create a new property on your databound class called NameInfo or something and do the conversion from that.

Silverlight bind collection to Combobox in DataForm using MVVM

I have this problem, I've got Silverlight app written using MVVM. I need to create DataForm which is binded to property on ViewModel and I want to add ComboBox and fill it with values from other collection in the same ViewModel.
Code:
<dataFormToolkit:DataForm CurrentItem="{Binding NewUser, Mode=TwoWay}" AutoGenerateFields="False" Height="298">
<dataFormToolkit:DataForm.EditTemplate>
<DataTemplate>
<StackPanel>
<dataFormToolkit:DataField Label="Email">
<TextBox Text="{Binding Email, Mode=TwoWay}"/>
</dataFormToolkit:DataField>
<dataFormToolkit:DataField Label="Język">
<ComboBox ItemsSource="{Binding Path=Languages, Mode=TwoWay}"/>
</dataFormToolkit:DataField>
</StackPanel>
</DataTemplate>
</dataFormToolkit:DataForm.EditTemplate>
</dataFormToolkit:DataForm>
All this is handled by NewAccountVM which has these properties:
private User newUser;
public User NewUser {
get
{
return newUser;
}
set
{
if (value != newUser)
{
newUser = value;
RaisePropertyChanged("NewUser");
}
}
}
private ObservableCollection<Language> languages;
public ObservableCollection<Language> Languages
{
get { return languages; }
set
{
if (languages != value)
{
languages = value;
RaisePropertyChanged("Languages");
}
}
}
Now, all this works besides adding ItemsSource to ComboBox. I've found many examples showing how fill CB in CodeBehind, but like I said I want to do this in MVVM-Style :)
I understand that, ComboBox inherited DataContext from DataForm, and this ItemsSource="{Binding Path=Languages, Mode=TwoWay}" will not work, but I have no idea how to achieve my goal.
Can somebody help me?
1) Declare the viewmodel to the view in the resources section.
<UserControl.Resources>
<local:MyViewModel x:Key="myViewModel" />
</UserControl.Resources>
2) Bind the ComboBox to the collection property on the viewmodel.
<ComboBox ItemsSource="{Binding Path=Languages,
Source={StaticResource myViewModel},
Mode=TwoWay}"/>
you can set the Data Context in XAML to your static resource like so:
<UserControl.DataContext>
<Binding Source="{StaticResource myViewModel}" />
</UserControl.DataContext>
Scenario A:
1. Assume you wish to populate a combo with all the membership Roles, and allow the client to select the role and assign to the User :
i.e. ObjectA : Aspnet_Role
i.e. ObjectB : User
Let us say User.MembershipRoleId is to be bound to Aspnet_Role.RoleId
Dataform is bound to ObjectB
Combobox in dataform is populated with List
In XAML write the following:
<Combobox DisplayMemberPath="RoleName"
SelectedValue="{Binding MembershipRoleId,Mode=TwoWay}" SelectedValuePath="RoleId" />
here the mapping is, ObjectB.MembershipRoleId=ObjectA.RoleId
Scenario B:
1. If you do not want to explicitly define by the way in ScenarioA, then in that case, define a ForeignKey-PrimaryKey relationship between the tables in the database like
ForeignKey -> User.MembershipId
PrimaryKey -> Aspnet_Roles.RoleId
2. From the ADO.NET (.edmx) file, update the model from the database, you will observe that in the User entity there is an association made upon entity Aspnet_Roles
3. In XAML write the code as below to bind the combobox, to the desired field of the Dataform
<Combobox DisplayMemberPath="RoleName" SelectedItem="{Binding MembershipRoleId,Mode=TwoWay}" .... />

Resources