![]()
Once we have created the project, we need copy across the WebCamCapture.csproj file from Samuel’s project. Then we rename the UserControl1 to WebCamControl to better reference latter in our USD Custom Control.
We also need to add a small public method to the WebCamControl to allow use to obtain the image that has been captured, so we open the WebCamControl.cs file and add the following to the bottom:
publicbyte[] GetImageData()
{
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
ImgWebCam.Image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
return memoryStream.ToArray();
}
Here we are simply using a memory stream to save the image to, and then we return the byte array which we need to save to CRM.
In the main CameraControl project we need to reference the WebCamCapture project so that we can use the control.
In the USDControl xaml we add a grid to lay everything out correctly, three buttons, and the WindowsFormsHost control which contains our WebCamControl:
<USD:DynamicsBaseHostedControl x:Class="TSG.MSCrm6.USD.CameraControl.USDControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:USD="clr-namespace:Microsoft.Crm.UnifiedServiceDesk.Dynamics;assembly=Microsoft.Crm.UnifiedServiceDesk.Dynamics"
mc:Ignorable="d"
Height="800" Width="800"
xmlns:controls="clr-namespace:WebCamCapture;assembly=WebCamCapture">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ToolBarTray Name="ProgrammableToolbarTray" Grid.Row="0" Focusable="false"/>
<!-- this is where any toolbar assigned to this control will go -->
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<WindowsFormsHost Height="500" Grid.RowSpan="2" Grid.ColumnSpan="3" Grid.Column="0" Grid.Row="0" Width="500">
<controls:WebCamControl x:Name="WebCamControl" Height="500" Width="500" Margin="0,0,0,0"/>
</WindowsFormsHost>
<Button x:Name="btnStart" Grid.Row="4" Grid.Column="0" Content="Start" Click="btnStart_Click" Height="50" Width="100"/>
<Button x:Name="btnStop" Grid.Row="4" Grid.Column="1" Content="Stop" Click="btnStop_Click" Height="50" Width="100"/>
<Button x:Name="btnSave" Grid.Row="4" Grid.Column="2" Content="Save" Click="btnSave_Click" Height="50" Width="100"/>
</Grid>
</Grid>
</USD:DynamicsBaseHostedControl>
We name the controls accordingly and create three Click events.
privatevoid btnStart_Click(object sender, RoutedEventArgs e)
{
this.WebCamControl.Start();
}
privatevoid btnStop_Click(object sender, RoutedEventArgs e)
{
this.WebCamControl.Stop();
}
privatevoid btnSave_Click(object sender, RoutedEventArgs e)
{
var session = (AgentDesktopSession)localSessionManager.ActiveSession;
if (session != null&& session.Customer != null)
{
var entity = ((DynamicsCustomerRecord)session.Customer.DesktopCustomer).InitialEntity;
var img = this.WebCamControl.GetImageData();
using (var serviceProxy = this._client.CrmInterface.OrganizationServiceProxy)
{
Entity newEntity = newEntity(entity.LogicalName);
newEntity.Id = entity.Id;
newEntity["entityimage"] = img;
serviceProxy.Update(newEntity);
}
MessageBox.Show("Saved");
}
}
Within the Start and Stop events, we call the WebCamCapture control’s Start and Stop methods.
Within the Save event we get the current Active Session, and validate whether a Customer has been selected by the standard USD Search feature. If a customer has been selected, then we get the initial CRM entity, we get the Image Data from the WebCamCapture control and simply assign the byte array to the entityimage property and call an Update on the CRM entity.
To ensure that we only allow users to save a captured image for a customer, we modify the NotifyContextChange event, that is called every time the context we are working on changes within the USD.
publicoverridevoid NotifyContextChange(Microsoft.Uii.Csr.Context context)
{
base.NotifyContextChange(context);
var session = (AgentDesktopSession)localSessionManager.ActiveSession;
if (session != null&& session.Customer != null)
{
EnableButtons(true);
}
else
{
EnableButtons(false);
}
}
Here we are simply checking to see if a customer has been selected, and if it has then we enable the three buttons we added earlier.
Before we can use the control, we need to add it to CRM so that when the USD starts, it knows that it needs to load it, and to display it.
So we go into CRM, and Add a new Hosted Control:
1. We specify the name, and display name
2. Set the USD Component to USD Hosted Control
3. Select Application is Global
4. Assign the Control to the MainPanel Display Group
5. Enter the Assembly URI as TSG.MSCrm6.USD.CameraControl
6. Enter the Assembly Type as TSG.MSCrm6.USD.CameraControl.USDControl
7. Click Save.
That is pretty much it!
How do we test our Controls?
Now we want to test our custom control, so we all we need to do is set the Startup project in visual studio to the TSG.MSCrm6.USD.CameraControl project.
We set the build output path to C:\Program Files\Microsoft Dynamics CRM USD\USD folder so that the dll’s are deployed when we debug.
Then we set the debug Start Action to Start External Program and browse to the USD application:
C:\Program Files\Microsoft Dynamics CRM USD\USD\UnifiedServiceDesk.exe
Finally we can start debugging which will in turn start the USD application up, and we see our custom hosted control as a new tab within the USD.
Now we can click on the Search button from the top menu, and Select an Account from the Accounts list, which causes our context to change and enable the three buttons on the Webcam Control.
Then we can click the TSG Webcam Control tab, click Start and then Stop to capture the customer’s picture, and finally click on the Save button to upload the picture to the customer record in CRM.
Hopefully you can see that it’s quite easy to create a custom hosted control in the Unified Service Desk.
Until next time…
@simonjen1