Binding a ComboBox
We have a new requirement. We want to add a configuration entry called DefaultColor. It can take one of three values - "Black", "Blue" or "Red". When the user selects a new DefaultColor we will save it in the Config table and change the color of the labels.
Note: To keep this as simple as possible I have not implemented an ideal database design.
1. Create a new table in the MVVM_Walkthrough database and populate it with the following SQL script.
USE [MVVM_Walkthrough]
GO
CREATE TABLE [dbo].[Colors](
[ColorName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Colors] PRIMARY KEY CLUSTERED
(
[Color] ASC
) ON [PRIMARY]
GO
2. Now populate the new table
INSERT INTO Colors VALUES ('Black')
INSERT INTO Colors VALUES ('Blue')
INSERT INTO Colors VALUES ('Red')
3. We always work from the Model to the ViewModel to the View. In the solution explorer double-click on MVVM_Walkthrough_Model.edmx
4. Right click in the Model's client area and select "Update Model from Database"
5. In the Update Wizard open the tables and select the Colors table. Click [Finish]
6. You now have a new table called Color in your Model.
7. Now we can update the ViewModel. We need to create a new config type property that will hold a default color that was selected from the list of Colors. Add the following code in the MainWindowViewModel constructor. This will initialize a property called DefaultColor.
Dim dc = (From a In Model.Configs Select a Where a.[Key] = "DefaultColor").ToList()
If dc.Count > 0 Then
Me.DefaultColor = dc(0)
Else
DefaultColor = New Config()
DefaultColor.Key = "DefaultColor"
DefaultColor.Value = "Black"
Model.Configs.Add(DefaultColor)
End If
8. Now we need to define this new property. Like the ApplicationName property there is a private member and a public property. The definition looks like this...
Private _DefaultColor As Config
Public Property DefaultColor As Config
Get
Return _DefaultColor
End Get
Set(value As Config)
If Not value.Equals(_DefaultColor) Then
_DefaultColor = value
NotifyPropertyChanged("DefaultColor")
End If
End Set
End Property
9. Now we have a way to capture and store the default color in the Config table. We can now create and populate a property that will hold a list of valid colors. Add the following code to the MainWindowViewModel constructor. Unlike the other properties we have created, this one will not be initialized if it is missing.
Dim col = (From a In Model.Colors Select a).ToList
Me.Colors = New ObservableCollection(Of Color)(col)
10. Now add the definition of the new Colors property. We use an observable collection instead of a list so that if any colors are added or removed in code all the bound controls will be updated too. We don't need this feature in this walk through but it is a good habit to get into. If you didn't realize it yet, we need to import System.Collections.ObjectModel.
Private _Colors As ObservableCollection(Of Color)
Public Property Colors As ObservableCollection(Of Color)
Get
Return _Colors
End Get
Set(value As ObservableCollection(Of Color))
If Not value.Equals(_Colors) Then
_Colors = value
NotifyPropertyChanged("Colors")
End If
End Set
End Property
11. Now our ViewModel has a default color config property and a list of valid colors. We can enhance the View to utilize these new properties. In the MainWindow.xaml add another RowDefinition and move the button down to Grid.Row="2"
12. Build the application so the new properties become available and add the following XAML to create another label and a combobox. The combobox itemssource is bound to the Colors collection and the SelectedValue is bound to the DefaultColor property.
<Label Grid.Row="1" Grid.Column="0" Content="{Binding Path=DefaultColor.Key}"/>
<ComboBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Path=Colors}" SelectedValuePath="ColorName" DisplayMemberPath="ColorName" SelectedValue="{Binding DefaultColor.Value}"/>
13. If we run the application now we see it works correctly and saves the new default color to the database. But there is one more requirement we have not fulfilled - we need the foreground color of the labels to change when the default color is changed. We can bind them to DefaultColor property with a style so we only have to do it once. Add the following XAML.
<Window.Resources>
<Style TargetType="Label">
<Setter Property="Foreground" Value="{Binding DefaultColor.Value}"/>
</Style>