Sign Silverlight XAP with TFS Build

I have a Silverlight application that is set up for Continuous Integration with Team Foundation Server. As part of the build, I needed to sign the XAP with a certificate. To accomplish this I will be using a command line tool SignTool.exe. The tool is automatically installed with Visual Studio and it has to exist on the TFS Server.

Steps below walk through the setup process.

1) Check-in the certificate into TFS. This must be done so that the build server downloads it into the workspace.

2) Update the Post-build event on the Silverlight project

In Project Properties, select ‘Compile’ option, then select the ‘Build Events…’ button.

image

We will be modifying Post-build event command line.  Select the ‘Edit Post-build …’ button.

clip_image004

Enter the SignTool command to execute:

"C:\Program Files (x86)\Windows Kits\8.0\bin\x86\SignTool.exe" sign /v /f
$(SolutionDir)\..\MyCert.pfx /p CertPassword $(TargetName).xap

Specify the path to the certificate relative to the solution directory so that it can be found during the Build.

3) Verify that your build definition is set up to download the certificate into its workspace.

Silverlight Telerik Transitions with User Controls

 

I was looking to implement Silverlight Telerik Transitions in my Silverlight 5 application with User Controls to walk a user through a wizard.  My initial approach was to use a Visual State Manager, which would allow me to keep all the UI logic in the XAML.  This did not work well with Telerik Transitions.  I decided to use DataTriggers that modified the state of the UI  based on a WizardState enumeration on my View Model.

View Model

 
Namespace ViewModels.Employee
 
    Public Class EmployeeViewModel
        Inherits BaseViewModel
 
 
#Region "Properties"
 
        Private _employeeSetupState As EmployeeSetupStateEnum
 
        Public Property EmployeeSetupState As EmployeeSetupStateEnum
            Get
                Return _employeeSetupState
            End Get
            Set(ByVal value As EmployeeSetupStateEnum)
                If _employeeSetupState <> value Then
                    _employeeSetupState = value
                    NotifyPropertyChanged("CanMoveForward")
                    NotifyPropertyChanged("CanMoveBack")
                    NotifyPropertyChanged("EmployeeSetupState")
                End If
            End Set
        End Property
 
        Public ReadOnly Property CanMoveForward() As Boolean
            Get
                Dim newState As Integer = EmployeeSetupState + 1
                If [Enum].IsDefined(GetType(EmployeeSetupStateEnum), newState) Then
                    Return True
                End If
 
                Return False
            End Get
        End Property
 
        Public ReadOnly Property CanMoveBack() As Boolean
            Get
                Dim newState As Integer = EmployeeSetupState - 1
                If [Enum].IsDefined(GetType(EmployeeSetupStateEnum), newState) Then
                    Return True
                End If
 
                Return False
            End Get
        End Property
 
        ' The Properties for the View Models are defined here.
 
#End Region
 
#Region "Base Overrides/Overloads"
 
        Public Overrides Sub Initialize()
            MyBase.Initialize()
 
            EmployeeSetupState = 0
            InitializeStep()
        End Sub
 
#End Region
 
#Region "Public Methods"
 
        Public Sub NextStep()
 
            If CanMoveForward Then
                EmployeeSetupState = CType(EmployeeSetupState + 1, EmployeeSetupStateEnum)
                InitializeStep()
            End If
 
        End Sub
 
        Public Sub PreviousStep()
 
            If CanMoveBack Then
                EmployeeSetupState = CType(EmployeeSetupState - 1, EmployeeSetupStateEnum)
                InitializeStep()
            End If
 
        End Sub
 
#End Region
 
#Region "Private Methods"
 
        Private Sub InitializeStep()
 
            Select Case EmployeeSetupState
                Case EmployeeSetupStateEnum.EmployeeGeneralInformationState
                    EmployeeGeneralInformationViewModel.Initialize()
                Case EmployeeSetupStateEnum.EmployeeAddressInformationState
                    EmployeeAddressInformationViewModel.Initialize()
                Case EmployeeSetupStateEnum.EmployeeContactInformationState
                    EmployeeContactInformationViewModel.Initialize()
                Case EmployeeSetupStateEnum.EmployeeCommentsState
                    EmployeeCommentsViewModel.Initialize()
            End Select
 
        End Sub
 
#End Region
 
    End Class
 
    ''' <summary>
    ''' States of the Employee setup process. These steps
    ''' are executed in the order specified.
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum EmployeeSetupStateEnum
        EmployeeGeneralInformationState
        EmployeeAddressInformationState
        EmployeeContactInformationState
        EmployeeCommentsState
    End Enum
 
End Namespace

In the code above, I have an enumeration that specifies valid states for my employee setup process (specified in the order I want to show these states) and a property in my View Model that holds the current state of the employee setup process. I have a trigger that calls the Initialize() method on my View Model when the page loads.  During the initialization process, my EmployeeSetupState is set to the first step and the view model for that step is initialized by calling the InitializeStep() method.  I have a property that determines if the current EmployeeSetupState has a previous or next step.  My View Model also holds a reference to the View Models for each of the User Controls that make up my employee setup states (not shown in the code above).

View

<UserControl.Resources>
    <vm:EmployeeViewModel x:Name="ViewModel"/>
</UserControl.Resources>
 
<Grid xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Name="LayoutRoot">
 
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" MinHeight="250" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
 
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <ic:CallMethodAction MethodName="Initialize"
                                 TargetObject="{Binding Mode=OneWay}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
 
    <telerik:RadTransitionControl Content="{Binding EmployeeSetupState}">
        <telerik:RadTransitionControl.Transition>
            <telerik:FadeTransition />
        </telerik:RadTransitionControl.Transition>
        <telerik:RadTransitionControl.ContentTemplate>
            <DataTemplate>
                <Grid Margin="5,10,5,10">
 
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
 
 
                    <uc:EmployeeGeneralInformationView x:Name="EmployeeGeneralInformationView"
                        Visibility="Collapsed"
                        DataContext="{Binding Source=ViewModel, Path=EmployeeGeneralInformationViewModel, Mode=TwoWay}" />
                    <uc:EmployeeAddressInformationView x:Name="EmployeeAddressInformationView"
                        Visibility="Collapsed"
                        DataContext="{Binding Source=ViewModel, Path=EmployeeAddressInformationViewModel, Mode=TwoWay}" />
                    <uc:EmployeeContactInformationView x:Name="EmployeeContactInformationView"
                        Visibility="Collapsed"
                        DataContext="{Binding Source=ViewModel, Path=EmployeeContactInformationViewModel, Mode=TwoWay}" />
                    <uc:EmployeeCommentsView x:Name="EmployeeCommentsView"
                        Visibility="Collapsed"
                        DataContext="{Binding Source=ViewModel, Path=EmployeeCommentsViewModel, Mode=TwoWay}" />
 
                    <i:Interaction.Triggers>
                        <ei:DataTrigger Binding="{Binding Converter={StaticResource EnumToStringConverter}}"
                                        Value="EmployeeGeneralInformationState">
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Visible"
                                TargetName="EmployeeGeneralInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeAddressInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeContactInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeCommentsView" />
                        </ei:DataTrigger>
                        <ic:DataTrigger Binding="{Binding Converter={StaticResource EnumToStringConverter}}"
                                        Value="EmployeeAddressInformationState">
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeGeneralInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Visible"
                                TargetName="EmployeeAddressInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeContactInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeCommentsView" />
                        </ic:DataTrigger>
                        <ic:DataTrigger Binding="{Binding Converter={StaticResource EnumToStringConverter}}"
                                        Value="EmployeeContactInformationState">
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeGeneralInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeAddressInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Visible"
                                TargetName="EmployeeContactInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeCommentsView" />
                        </ic:DataTrigger>
                        <ic:DataTrigger Binding="{Binding Converter={StaticResource EnumToStringConverter}}"
                                        Value="EmployeeCommentsState">
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeGeneralInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeAddressInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Collapsed"
                                TargetName="EmployeeContactInformationView" />
                            <ic:ChangePropertyAction
                                PropertyName="Visibility" Value="Visible"
                                TargetName="EmployeeCommentsView" />
                        </ic:DataTrigger>
                    </i:Interaction.Triggers>
 
                </Grid>
            </DataTemplate>
        </telerik:RadTransitionControl.ContentTemplate>
    </telerik:RadTransitionControl>

    <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
        <Button x:Name="PreviousButton" Content="&lt; Previous"  HorizontalAlignment="Right"
                Visibility="{Binding CanMoveBack, Converter={StaticResource BoolToVisibilityConverter}}"
                Margin="5"  Style="{StaticResource ButtonPrimaryStyle}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ic:CallMethodAction MethodName="PreviousStep"
                                         TargetObject="{Binding Mode=OneWay}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
        <Button x:Name="NextButton" Content="Next &gt;" Width="70" HorizontalAlignment="Right"
                Visibility="{Binding CanMoveForward, Converter={StaticResource BoolToVisibilityConverter}}"
                Margin="5" Style="{StaticResource ButtonPrimaryStyle}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ic:CallMethodAction MethodName="NextStep"
                                         TargetObject="{Binding Mode=OneWay}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
 
    </StackPanel>
 
</Grid>

In my View, I bind the Content property of RadTransitionControl to the EmployeeSetupState from my View Model.  The transitions happen each time the state change occurs.  The data triggers control what view displays depending on the current employee setup state.  In the data triggers I use the ChangePropertyAction to set the Visibility of the User Controls.  This separates my View Model code to only determine and set the state of the setup process and my View handles the display.

Silverlight 4 Telerik Scheduler Issue

Telerik controls version 2010.1.422.1040

I recently took over a Silverlight Telerik scheduler which was having an issue with displaying appointments on a resource view.   The only way I could get appointments to display is if “DisplayEmptyGroup” property on the scheduler was set to true.  All the appointments were assigned to a resource, but would not display on the scheduler.

The issue was the assignment of the resources to appointments.  The appointments were loaded and added to the Telerik appointment collection.  Then each appointment in the collection was looped through and assigned to the resource.  So as the appointments were added to the collection, they defaulted to an empty resource group since it was not yet assigned to the resource.  For some reason, since the empty group is not displayed (“DisplayEmptyGroup”  set to false), the appointments did not show up on the scheduler when the resource was eventually assigned to the appointment.

To fix the problem, I assigned the resource to an appointment before adding it to the collection.  Problem solved!!!

LINQ Lazy Loading

I was experiencing some performance issues in my Silverlight application and got it narrowed down to the mapping of the domain objects.  After running SQL profiler and doing some research I figured out that it was due to Linq lazy loading.

As an example if I have the following data structure:

Employee_EmployeePosition

I would have an “EmployeePosition” domain object and an “Employee” domain object.  I will use the following Linq statement to bring back all Employee Positions:

  1. using (var dc = new DataClasses1DataContext())
  2. {
  3.     var postiions = dc.EmployeePositions.ToList();
  4. }

Linq lazy loading is enabled by default, so by executing the above query Linq will only bring back Employee Positions.  If I am only looking for Employee Positions everything works as expected.  The issue appears if I want to bring back the Employee information for each position.  Since I have a foreign key relationship between “Employee” and “EmployeePosition”, my dbml has “one to many” association between them.  This allows me to write the following mapping to my object that I return to my Silverlight application:
  1. var myEmployees = postiions.Select(x => new EmployeeWithPosition
  2.                     {
  3.                         FirstName = x.Employee.FirstName,
  4.                         LastName = x.Employee.LastName,
  5.                         Position = x.Position
  6.                     }).ToList();

When executing above code, there is a separate call made to the database to get the “FirstName” then another call to get the “LastName” for each of the “EmployeePosition” objects due to LINQ lazy loading (default).  So if I have 10 employee positions, there are 20 additional calls made to the database.

There are a few solutions to solve this issue:

    1. Disable lazy loading for the entire dbml file. 
    2. Specify “DataLoadOptions” on the Data Context.  This is a valid option if you do not re-use the Data Context.
    3. Use projection to load only necessary data.

The best option for my situation was to use projection to load my data.  To do this I extended my existing Employee domain object by creating a partial “Employee” class and adding a string “Position” property.  Then I used projection to load my data to the Employee domain object.

  1. using (var dc = new DataClasses1DataContext())
  2. {
  3.     var myEmployees = dc.EmployeePositions.Select(x => new Employee
  4.     {                    
  5.         FirstName = x.Employee.FirstName,
  6.         LastName = x.Employee.LastName,                    
  7.         Position = x.Position
  8.     }).ToList();
  9. }

When I executed above code I got the following run-time error:

Explicit construction of entity type ‘Employee’ in query is not allowed.

After doing a little research I discovered that projection to a domain object is not allowed. As a work around, I used my “EmployeeWithPosition” custom object which only contains properties that I am interested in from the “Employee” and “EmployeePosition” domain objects to project my data.

  1. using (var dc = new DataClasses1DataContext())
  2.             {
  3.                 var myEmployees = dc.EmployeePositions.Select(x => new EmployeeWithPosition
  4.                 {                    
  5.                     FirstName = x.Employee.FirstName,
  6.                     LastName = x.Employee.LastName,                    
  7.                     Position = x.Position
  8.                 }).ToList();
  9.             }

Silverlight Telerik Editable GridView with MVVM – Part 3

This is the final part of the Telerik Editable GridView Series. In Part 1 I talked about the Model and in Part 2 I covered the View Model. In this post I will be discussing the View portion of the MVVM pattern.

I will start out with the xaml for the GridView.

[sourcecode language=’vb’]

xmlns:telerikGridView=”clr-namespace:Telerik.Windows.Controls;
assembly=Telerik.Windows.Controls.GridView”
xmlns:telerikData=”clr-namespace:Telerik.Windows.Controls;
assembly=Telerik.Windows.Controls.Data”

[/sourcecode]

[sourcecode language=’xml’]





















[/sourcecode]

I bind the GridView item source to the “EmployeeList” in the View Model. Each column is bound to a property on the Employee Model. Since my model implements System.ComponentModel.INotifyPropertyChanged, the GridView is updated each time any property that I am bound to on the model changes. I used a templated column to represent the “IsActive” boolean column. For the templated column I specify binding in each of the cell templates and on the column. The binding on the column is used by the GridView for filtering and sorting.

Next, I will go through the code-behind of the View.

[sourcecode language=’vb’]

Partial Public Class EmployeeMaintenancePage
Inherits UserControl

Private _vm As EmployeeMaintenanceViewModel

”’

”’ Constructor
”’

”’
Public Sub New()
InitializeComponent()
End Sub

#Region “Event Handlers”

”’

”’ I clear my sort and filter before adding a new Employee. This is
”’ necessary because if the new row does not fit the current filter, it
”’ will not display. Also, by clearing the sort, we force the newly added
”’ row to the bottom of the grid.
”’

”’ ”’ ”’
Private Sub EmployeeGridView_AddingNewDataItem(ByVal sender As System.Object, ByVal e As Telerik.Windows.Controls.GridView.GridViewAddingNewEventArgs)
EmployeeGridView.FilterDescriptors.Clear()
EmployeeGridView.SortDescriptors.Clear()
e.NewObject = _vm.GetNewEmployee()
End Sub

”’

”’ Reload from the row cache if edit was cancelled, otherwise
”’ save to the database.
”’

”’ ”’ ”’
Private Sub EmployeeGridView_RowEditEnded(ByVal sender As System.Object, ByVal e As Telerik.Windows.Controls.GridViewRowEditEndedEventArgs)
If e.EditAction = Telerik.Windows.Controls.GridView.GridViewEditAction.Cancel Then
_vm.ReloadEmployeeFromCache(CType(e.Row.DataContext, EmployeeModel))
Else
_vm.UpdateEmployee(TryCast(e.Row.DataContext, EmployeeModel))
End If
End Sub

”’

”’ Call the delete method on the View Model to delete employee. GridView will get
”’ updated when the item is removed from the “EmployeeList” on the view model.
”’

”’ ”’ ”’
Private Sub EmployeeGridView_Deleting(ByVal sender As System.Object, ByVal e As Telerik.Windows.Controls.GridViewDeletingEventArgs)
_vm.DeleteEmployee(CType(e.Items(0), EmployeeModel).Id)
e.Cancel = True
End Sub

”’

”’ Store the current copy of the row on Selection Changed. In a case when an edit
”’ is cancelled, the stored value is used to reload row with original values.
”’

”’ ”’ ”’
Private Sub EmployeeGridView_SelectionChanged(ByVal sender As System.Object, ByVal e As Telerik.Windows.Controls.SelectionChangeEventArgs)
If e.AddedItems.Count > 0 Then
_vm.CurrentRowCache = CType(e.AddedItems(0), EmployeeModel).Clone()
End If
End Sub
#End Region

#Region “Public Methods”

”’

”’ Load the View Model and bind it to the View.
”’

”’
Public Sub Load()
_vm = New EmployeeMaintenanceViewModel()
_vm.Load()
Me.DataContext = _vm
End Sub

#End Region

End Class

[/sourcecode]

In the code-behind of the View, I mainly handle the events and call my View Model to process the logic. This allows me to unit test the logic in my View Model.

Silverlight Telerik Editable GridView with MVVM – Part 2

This is the continuation from Part 1 where I walked through creating my Model. The next step is to create a View and a View Model. There should only be one View Model per View. I will try to take advantage of xaml binding where possible.

Following is my View Model.

View Model
  1. Imports System.Collections.ObjectModel
  2. Imports System.ComponentModel
  3.  
  4. Public Class EmployeeMaintenanceViewModel
  5.     Implements INotifyPropertyChanged
  6.  
  7.     Public Event PropertyChanged( _
  8.             ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
  9.  
  10.     Protected Sub NotifyPropertyChanged(ByVal propertyName As String)
  11.         RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  12.     End Sub
  13.  
  14. #Region "Private Members"
  15.  
  16.     Private _employeeGateway As EmployeeGateway
  17.     Private _currentRowCache As EmployeeModel
  18.     Private _employeeList As ObservableCollection(Of EmployeeModel) =  _
  19.             New ObservableCollection(Of EmployeeModel)
  20.  
  21. #End Region
  22.  
  23. #Region "Constructors"
  24.  
  25.     Public Sub New()
  26.  
  27.     End Sub
  28.  
  29. #End Region
  30.  
  31. #Region "Properties"
  32.  
  33.     Public Property CurrentRowCache() As EmployeeModel
  34.         Get
  35.             Return _currentRowCache
  36.         End Get
  37.         Set(ByVal value As EmployeeModel)
  38.             _currentRowCache = value
  39.         End Set
  40.     End Property
  41.  
  42.     Public Property EmployeeList() As ObservableCollection(Of EmployeeModel)
  43.         Get
  44.             Return _employeeList
  45.         End Get
  46.         Set(ByVal value As ObservableCollection(Of EmployeeModel))
  47.             _employeeList = value
  48.         End Set
  49.     End Property
  50.  
  51. #End Region
  52.  
  53. #Region "Public Methods"
  54.  
  55.     'use WCF to load all employees.
  56.     Public Sub Load()
  57.         'clear the list prior to loading.
  58.         EmployeeList.Clear()
  59.  
  60.         _employeeGateway = New EmployeeGateway()
  61.         _employeeGateway.FindAllEmployees(AddressOf OnEmployeesLoaded)
  62.  
  63.     End Sub
  64.  
  65.     Public Function GetNewEmployee() As EmployeeModel
  66.         Dim emp As New EmployeeModel()
  67.  
  68.         'default to active, set uniqueId to map employee back
  69.         'when returned from a save
  70.         emp.IsActive = True
  71.         emp.UniqueId = Guid.NewGuid
  72.         Return emp
  73.     End Function
  74.  
  75.     Public Sub UpdateEmployee(ByVal emp As EmployeeModel)
  76.         emp.IsModified = True
  77.         SaveEmployee(emp)
  78.     End Sub
  79.  
  80.     Public Sub DeleteEmployee(ByVal id As Integer)
  81.         Dim emp As EmployeeModel = EmployeeList.Where(Function(x) x.Id = id).SingleOrDefault()
  82.         If id > 0 Then
  83.             emp.IsDeleted = True
  84.             SaveEmployee(emp)
  85.         Else
  86.             EmployeeList.Remove(emp)
  87.         End If
  88.  
  89.     End Sub
  90.  
  91.     'in a case of a cancel edit, i reload employee with the values stored in the
  92.     'row cache before edit.
  93.     Public Sub ReloadEmployeeFromCache(ByVal emp As EmployeeModel)
  94.         If CurrentRowCache Is Nothing Then
  95.             Exit Sub
  96.         End If
  97.  
  98.         With emp
  99.             .IsActive = CurrentRowCache.IsActive
  100.             .FirstName = CurrentRowCache.FirstName
  101.             .LastName = CurrentRowCache.LastName
  102.         End With
  103.     End Sub
  104.  
  105. #End Region
  106.  
  107. #Region "Private Methods"
  108.  
  109.     'Call WCF to save employee
  110.     Private Sub SaveEmployee(ByVal emp As EmployeeModel)
  111.         _employeeGateway = New EmployeeGateway()
  112.         _lookupGateway.SaveEmployee(AddressOf OnEmployeeSaved, emp)
  113.     End Sub
  114.  
  115.     Private Sub UpdateRecord(ByVal updatedEmployee As EmployeeModel)
  116.         Dim emp As EmployeeModel
  117.  
  118.         'if uniqueId is not Guid.Empty, it's a new add, use the guid to find it in the list.
  119.         If updatedEmployee.UniqueId <> Guid.Empty Then
  120.             emp = EmployeeList.Where(Function(l) l.UniqueId = _
  121.                                          updatedEmployee.UniqueId).SingleOrDefault
  122.         Else
  123.             emp = EmployeeList.Where(Function(l) l.Id = _
  124.                                          updatedEmployee.Id).SingleOrDefault
  125.         End If
  126.  
  127.         'check if employee was found
  128.         If emp IsNot Nothing Then
  129.             If updatedEmployee.IsDeleted Then
  130.                 EmployeeList.Remove(emp)
  131.             Else
  132.                 'This data will be updated on the grid since I implemented
  133.                 'INotifiyPropertyChanged interface on my Model.
  134.                 With emp
  135.                     .Id = updatedEmployee.Id
  136.                     .FirstName = updatedEmployee.FirstName
  137.                     .LastName = updatedEmployee.LastName
  138.                     .IsActive = updatedEmployee.IsActive
  139.                 End With
  140.             End If
  141.         End If
  142.     End Sub
  143.  
  144. #End Region
  145.  
  146. #Region "Event Handlers"
  147.  
  148.     Private Sub OnEmployeesLoaded(ByVal employees As ObservableCollection(Of EmployeeModel))
  149.  
  150.         'each employee must be added to the observable collection so that
  151.         'it is reflected on the Grid.
  152.         For Each emp As EmployeeModel In employees
  153.             EmployeeList.Add(emp)
  154.         Next
  155.  
  156.     End Sub
  157.  
  158.     Public Sub OnEmployeeSaved(ByVal updatedEmployee As EmployeeModel)
  159.         If updatedEmployee IsNot Nothing Then
  160.             UpdateRecord(updatedEmployee)
  161.         End If
  162.     End Sub
  163.  
  164. #End Region
  165.  
  166. End Class

Review the comments in the code snippet for explanation. The goal is to place all the logic specific to UI in the View Model. The View Model should not be accessing any controls directly. The View knows about the View Model, but the View Model does not have a reference back to the View. The View Model basically bridges the gap between the View and the Model.

The View code behind will access controls in a case where direct binding is not available, but any logic should still be placed in the View Model. The View code behind will generaly handle events and make calls to the View Model. I will cover that in Part 3 of the post.