Saturday 29 June 2013

Dynamics CRM 2011 On-premises - Use “Execute AS” to call custom stored procedures

For one of our customers, we had created some custom stored procedures in a separate database with CRM plugins to replace their existing SQL triggers. We required these SPs “as is” because they were having very complex logic inside them and would have taken ample amount of time to re-write the complete logic in CRM plugins. Hence, We had just reused those objects and amended it to make them compliance with Dynamics CRM standards by fetching the data from filtered views instead of direct table hits. Like,

Select * from DBO. Account

was replaced with,

Select {required columns } from OrganisationName_MSCRM.dbo.FilteredAccount

Inside the Dynamics CRM plugins, we had written the code to connect to the custom database (using windows authentication connection string) and called the above stored procedures. However, surprisingly, the stored procedures did not return any data. Hence, one of our developers came to me with this problem. I knew that the problem is with Application Pool Identity. The CRM plugins are executing under the CRM Application Pool Identity user and that user does not have permission to access the CRM data.

image

The CRM filtered views run under the user security roles and do not return data if you don’t have configured the required privileges. Additionally, we must not configure the Dynamics CRM user as CRM application pool identity. Please refer below URL to know more about Security considerations for Microsoft Dynamics CRM 2011.

http://technet.microsoft.com/en-us/library/hh699825.aspx

Then, I suggested her to add the above application pool identity user to PrivUserGroup. (One of the auto-generated Active Directory groups.) But, in our case the identity pool user was already added in this group. To give complete CRM database access, it can also be added to SQLAccessGroup, however, the situation was same, and the identity was already added here too.

Eventually, we switched to user impersonation. There were two options; either we impersonate the user inside the plugin or at SQL server level. I had asked her to implement the latter one and she tried with “Execute AS” inside the stored procedure and it worked as per the expectation. Below is our complete solution.

1.  Add a new user in SQL server security logins, the security logins area is displayed in below screen shot.

image

OR

If you wish then you can use one of the existing users. However, this user must require sysadmin sever role to execute “Execute AS” command. Below link will help you to get more details on “Execute AS” (transact-SQL).

http://msdn.microsoft.com/en-us/library/ms181362.aspx

2. Use the above SQL user in your connection string to connect with custom database inside CRM plugins, as described below.

Data Source=myServer;Initial Catalog=myDataBase;User Id=myUsername; Password=myPassword;Integrated Security=false

3. Retrieve the domain name of logged in CRM user.

In plugin context you will always get the UserID via Context.UserID property, which is the GUID of the logged in CRM User. Use this value to retrieve the domain name of logged in CRM user from “systemuser” table. Keep this web service call in a common class/method inside your plugin solution, so that, the same can be reused in other plugin classes as well.

4. Pass the above domain name to your custom stored procedure as parameter which can be further used in “Execute AS” command, as shown in below stored procedure.

USE [DBName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TestProcedure] 
    @UserName NVARCHAR(100)
AS
BEGIN
    BEGIN TRY
        EXECUTE AS LOGIN =  @UserName 
        SELECT * FROM CRM_DB_Name.dbo.FilteredAccount
        REVERT;
    END TRY
    BEGIN CATCH
        REVERT;
    END CATCH
END

Note: Make sure you write the “REVERT” command to stop the user impersonation inside your stored procedure.

In this way we have impersonated the application pool identity user with the logged in CRM user. Thus, we can fetch the data from filtered views based on logged in user security roles.

I hope this would be helpful.

Saturday 1 June 2013

CRM 2011 On Premises - External Connector License

 

UPDATE: The External Connector License is obsoleted. The connector was removed from the pricelist in January 2014. From the quick reference guide:
"Access by external (third party) users is included with the Server License; you do not need CALs unless using Microsoft Dynamics CRM client applications. External users are users that are not either your or your affiliates’ employees, or your or your affiliates’ onsite contractors or onsite agents."

 

One of our customers, working on CRM 2011 on-premises, would like to provide the access of CRM data to external parties, like their service providers, customers and other contacts. At present, these people have been created as contacts in CRM. I was asked to prepare high level design, a work model that allows this group of people to access the Dynamics CRM data. I have prepared a design wherein we decided to give access to external parties via the existing web site of my customer. I have also explained that we require External Connector License for this implementation. However, as I never used it before, I would like to collect more details on External Connector License.

I thought once we purchase such uncommon license from Microsoft, they would allow us to assign it to one of the existing Dynamics CRM users and the credentials of that user can be consumed at web portal then to fetch/update CRM data. To validate my understanding, I put the same as question on different Dynamics CRM communities, forums and groups.

I found that my conception was wrong. The External Connector License is just a paper license, a trust license. It has nothing to do with the implementation. To validate the cost for this license, you can refer below link.

http://crmpublish.blob.core.windows.net/docs/Pricing_Licensing_Guide.pdf

You could also refer the below links that help me to confirm it.

http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/6843ac17-4946-4ac4-8e88-22a5fae3e425

http://www.linkedin.com/groups/Can-some-explain-Employee-Self-21231.S.99273324?trk=group_search_item_list-0-b-ttl

Note: The External Connector License is not applicable to Dynamics CRM 2011 online

Please feel free to update this post with your experience about External Connector License.

Saturday 27 April 2013

Dynamics CRM 2011 – Be careful while setting up an owner of workflow in production environments

Yesterday one of my customers had discussed about the functionality of uncomforting orders, which was stopped working unexpectedly. She said that everything was working well a week ago.

This customer works on Dynamics CRM 2011 online. So, being a system administrator on the same instance, I immediately tried to login to the production server, but unfortunately she had deactivated me as she wanted to assign the same license to one of their new sales team member. So, I asked her to invite me again and provide the admin rights to validate the problem. For, this functionality I had configured a workflow (process) to activate the fulfilled order. So, on very first step I did validate the System Jobs in Settings area. Over there, I found that the some of the workflow records were sitting in listening (waiting) mode, while some had executed successfully.

Upon further inspection, I had discovered that the waiting mode workflows were still owned by me. As she deactivated me on the production server, all the workflow jobs were waiting for me to be activated again. So, we instantly changed the owner of those workflows and resume the workflow jobs. Voila! Everything started working well then.

Hence, the learning is, we should not own the workflows in production environment of our customers, so that they do not face the above problem.

I hope this would be helpful.

Friday 12 April 2013

Vote me for "2013 TOP 100 MOST INFLUENTIAL MICROSOFT DYNAMICS PEOPLE"

Hello everybody,

I would like to draw your attention to the Microsoft Dynamics Most Influential Top 100 List for 2013.

I am pleased to tell you that I have been nominated and that we are now in the voting process.

If you believe that I deserve it then please spare a few seconds time and take part in below voting poll by giving your invaluable vote to “Ankit Shah”.

http://www.dynamicsworld.co.uk/the-top-100-most-influential-people-in-microsoft-dynamics-list-for-2013-page-1/

Saturday 6 April 2013

Dynamics CRM 2011 – Send an e-mail on a specific date

 

Currently, I came across a scenario where we had to configure a workflow to send an e-mail on a specified date value on an opportunity entity. On opportunity entity I had a date field “Date 1” and what we were required to do was to send an email to opportunity owner on a date specified in the Date 1 field value. To achieve this, I can configure a workflow with timeout or wait condition set on the Date 1 value.

First, I tried to make it work using the Timeout criteria but it seemed to fail our requirements when the date value is null. So, I decided to work with wait condition.

Following are the steps configured in workflow to meet the requirements:-

image

Step 1: Start workflow on Record Created and Record Fields change. In Record fields change select the Date1 field.

Step 2: Check if Date1 field is null. If the field is null then no need to set any wait condition.

Step 3: Since we have fired this workflow on field change also, we had to make sure that there should not be more than one workflow with wait condition. When opportunity record is created and Date 1 field contains data, a workflow record would be created in wait mode. At the same time, if somebody modifies the date 1 value for the same opportunity record then another workflow record should not be crated in waiting mode to be executed on that particular updated date value. Instead, the previously created workflow should be updated with new value. To achieve this we have taken a custom attribute here DateValue which is a two option field. Default value of DateValue is false. Once a date is entered the value of datevalue gets updated to true. This way we ensure that on field change we don’t create a new wait condition if one already exists.

Step 4: If the attribute value is false means there is no previously existing system job with wait condition. So, Add step of wait condition and set process execution time on or after the Date1 value. If the value is true means the workflow record was already created and nothing to do in that scenario.

Step 5: Add a Send Email step and configure required values.

I hope this would be helpful.

Friday 29 March 2013

Dynamics CRM 2011 – Limitations of Report Wizard (OOB)

 

Feature List

Report Wizard (OOB)

Custom SSRS Report - BIDS

Remarks

Grouping

Yes

Yes

-

Adding extra rows and columns

No

Yes

-

Expressions Based Values

No

Yes

-

Design, Font, Colour Change

No

Yes

No option available while creating report through wizard. Is possible after exporting and changing the report.

Context specific

Yes (By Default)

Yes

-

Group Summary

Yes (With limited functions)

Yes

Average, Maximum, Minimum, Percentage of total, Sum are the summary types that can be used in report wizard for a field.

Lookup Functionality

No

Yes

-

Hyperlink

No

Yes

-

Use of Sub Reports

No

Yes

-

Charts

Yes (Limited Type)

Yes

Only vertical bar chart, horizontal bar chart, line chart, pie chart are supported in report wizard.

Tools like line, list, image, sub report, gauge, map,
indicator, sparkline

No

Yes

 

Custom Code

No

Yes

 

Functions Available in Expressions

No

Yes

 

Hide Show based on expressions

No

Yes

 

Report filters

No

Yes

 

Parameters

No

Yes

There is no way to add new parameter to the report
through report wizard.

Header - Body - Footer

No

Yes

 

Page Nos. in footer

No

Yes

 

Accessing Current Date Time

No

Yes

 

Entities could be involved in generating a report

One primary entity and it's first level related entity

No such limitation

 

I hope this would be helpful. Please feel free to comment on this post with more limitations.

Friday 15 March 2013

Dynamics CRM - Trigger a workflow from JavaScript

 
Updated on – 24th Sep 2015
 
Recently I had a requirement to trigger a workflow on click of ribbon button when it meets certain criteria. Refer below link for calling JavaScript function from custom ribbon button.

http://ankit.inkeysolutions.com/2012/01/crm-2011-how-to-use-visual-ribbon.html

The criteria values are checked using JavaScript and if all criteria are satisfied then the workflow is to be triggered. The function below will take two inputs where entityId is the id of the record for which the workflow will execute and workflowProcessId is the id of the workflow which we want to execute.
function startWorkflow(entityId, workflowProcessId) {
  var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
   "<s:Body>" +
     "<Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
       "<request i:type=\"b:ExecuteWorkflowRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">" +
         "<a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">" +
           "<a:KeyValuePairOfstringanyType>" +
             "<c:key>EntityId</c:key>" +
             "<c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">" + entityId + "</c:value>" +
           "</a:KeyValuePairOfstringanyType>" +
           "<a:KeyValuePairOfstringanyType>" +
             "<c:key>WorkflowId</c:key>" +
             "<c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">" + workflowProcessId + "</c:value>" +
           "</a:KeyValuePairOfstringanyType>" +
         "</a:Parameters>" +
         "<a:RequestId i:nil=\"true\" />" +
         "<a:RequestName>ExecuteWorkflow</a:RequestName>" +
       "</request>" +
     "</Execute>" +
   "</s:Body>" +
 "</s:Envelope>";
 
  var requestURL = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/Organization.svc/web";
  var xmlHttpRequest = new XMLHttpRequest();
  xmlHttpRequest.open("POST", requestURL, false)
  xmlHttpRequest.setRequestHeader("Accept", "application/xml, text/xml, */*");
  xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
  xmlHttpRequest.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
  xmlHttpRequest.send(request);
}


That’s it. The above common method can be used to trigger workflow from JavaScript.

I hope this would be helpful.



Friday 8 March 2013

Dynamics CRM 4.0 to 2011 upgrade - ISV tab dilemma

Currently, I am working on one of my projects where in I was told to develop an upgrade plan, to upgrade an organization from CRM 4.0 to 2011. The customer uses couple of third party add-ons and these add-ons have applied some changes in ISV.config file in CRM 4.0. I have prepared my lists for upgrade and started with test runs, during this time I found some unwanted ISV tab(highlighted in below screen shot) on some of the in-built and custom entities.

image

After some binging, I came to know that this is by design. All Custom Menu and Grid Buttons of CRM 4.0 would be upgraded as new tab besides Customize tab in CRM 2011. To know more about this symptom, you can refer below link.

http://support.microsoft.com/kb/2501761

There are couple of solutions which could be applied to get rid of this ISV tab as explained below,

1. You can remove these buttons from CRM 4.0 via updating ISV.config file before upgrade.

2. You can change the RibbonDiffXml part of customization xml file, as described in above link after upgrading an organization.

If you want to apply second solution then you can use Ribbon Workbench tool for CRM 2011. You can download & import this add-on with the help of below URL.

http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx

And then,

1. Create a solution with just the application ribbon in it.

2. Find the ISV tab

3. Right click on it and select 'Un-customise Tab'

4. Publish your solution.

According to my knowledge the Visual Ribbon Editor tool does not support this feature as of now.

I hope this would be helpful.

Saturday 23 February 2013

Dynamics CRM 2011 - Unfulfilled order records – No code solution

In Dynamics CRM 2011, you have an option to fulfil an order record. Once you fulfil it you cannot modify that record further. Unlike lead and opportunity records, OOB, there is no action button on top ribbon bar that allows you to reopen the fulfilled order record. The very simple way to reopen it is to configure a workflow. One can create an on-demand workflow on order entity and change the status of the order record(s) from “Fulfilled” to “New”. Recently, one of my customers had the same requirement but with one constraint i.e. this action should be performed by users only with specific security roles. All system users cannot reopen the fulfilled orders.

To achieve this we can create our own custom ribbon button on Order record and replace the system button. There could be one configuration entity where system admin can select the security role(s) which can be validated later when user clicks on above custom ribbon button. If logged in user has any of the configured security roles then only that user can reopen an order.

However, I wished to develop this functionality without writing a single line of code. So, below is my no code solution.

My Solution

1. Create one custom entity say “Unfulfilled Orders”

2. Create new N:1 relationship with Order entity (A business required field)

3. Drag the mandatory order lookup control on a form

4. Create one workflow on this custom entity (created in step 1)

In workflow, first check the status of related order whether it is fulfilled or not.

If it fulfilled then only change its status to “New” as described in below screen shot.

image

5. On Administration tab, select the check box at the bottom of the window i.e.

“Automatically delete completed workflow jobs”

6. Change sitemap to place this custom entity at Settings – underneath Business tab.

7. Change the specific security role(s) which should have an access on the above custom entity.

8. Publish all customization changes.

9. Do not forget to activate the workflow.

And that’s it.

Here, I am done with my solution. Users who have permission on this entity can access it from Settings – Business area. I have configured the workflow to be triggered on two events, on creation of a new record or on change of related order record (change of orderid via lookup control) in edit mode. In both cases the above workflow will trigger and change the status of the related order to “New”. Moreover, it is a quite scalable solution; system administrator can allow/disallow this functionality to specific security role(s).

Please feel free to update this post with your no code solutions to reopen fulfilled order records, if any.

Saturday 9 February 2013

Dynamics CRM 2011 – Mapping of fields from Opportunity Products to Invoice Products

Recently, one of my customers would like to map couple of common custom attributes during execution of entire sales cycle. They are using the out of the box Dynamics CRM sales process. They have these attributes on Opportunity Product entity and want the same values to be auto populated with rest of the sales cycle. Like, when you create Quote record with Quote Products from an opportunity, the same custom attributes should be filled automatically for Quote Products. Likewise, the custom attributes should be populated when you create an Order with Order Products from a Quote and Invoice with Invoice Products from an Order.

Out of the box you cannot find such mappings on these relationships. So, to achieve this requirement, you can use below trick to generate the hidden mappings URLs.

On your development server/machine you just need to execute below query in SQL Management Studio to find out relationship GUID id for Opportunity Product and Quote Product entities.

SELECT    EntityMapId 
FROM      EntityMapBase 
WHERE     TargetEntityName='quotedetail' AND SourceEntityName='opportunityproduct' 


Use the above GUID in below URL and also change the organization name.

http://localhost:5555/[ORG_Name]/Tools/SystemCustomization/Relationships/Mappings/mappingList.aspx?mappingId=[Your_GUID]

Now, launch internet explorer and paste this URL at address bar. As displayed in below screenshot, you could see the list of all available mappings of the above two entities.

image

Click on New button to open below field mapping popup. Here, you are free to do your mappings.

image

In the same fashion, find out the mapping GUIDs for Quote Product to Order Product and Order Product to Invoice Product. Prepare their URLs as explained above and complete the attribute mappings.

Finally, add these entities to your unmanaged solution on your development organization. Export it as a managed solution and import the same on QA and Production environments. The same mappings should be applied to those organizations too. Moreover, the same managed solution can also be imported to CRM 2011 online or partner hosted.

I hope this will be helpful.

Reference:

http://crmconsultancy.wordpress.com/tailoring-the-product-selection-for-opportunities-and-quotes-in-dynamics-crm/productcataloguemapping-mscrm-fields-from-opportunity-product-to-quote-product/

Saturday 2 February 2013

Dynamics CRM 2011 - LookupSet Function in SSRS reports

 

Syntax

LookupSet(source_expression, destination_expression, result_expression, dataset)

LookupSet is generally used to retrieve a set of values from the specified dataset for a name/value pair where there is a 1-to-many relationship. For example, for a customer identifier in a table, you can use LookupSet to retrieve all the associated phone numbers for that customer from a dataset that is not bound to the data region.

The above is the description specified for use of LookupSet function. Yesterday, while creating a report I used the LookupSet function and overlooked the highlighted text. I used the LookupSet in a column expression within the tablix. The Dataset assigned to tablix was “DataSet2”.

image


In the LookupSet also I specified the same DataSet i.e. DataSet2 . While executing the query on DataSet, rows were fetched as required.


image


AS viewed above 8 distinct names could be viewed. But when running the report one row was not displayed in tablix but the distinct count i.e. 8 was correctly calculated on very first row of that column.

image

After spending few hours I found that the culprit was LookupSet function which was used in an expression of a column on same tablix . Both tablix and Lookupset function were using the same Dataset i.e. DataSet2.

image

According to the function description, the dataset that is not bound to the data region should be used whereas we were using the same dataset that was used for binding in the data region.

So, the solution is to create another dataset with fields that you want to Lookup. In the LookupSet function specify the newly created DataSet.

image

For me this fixed the weird behavior in displaying rows and the final results are displayed in below screen shot.


image

Friday 18 January 2013

CRM 2011 On-premises – Custom SSRS reports are blank, no data.

Did you ever add “Domain\MachineName$” as a User in Dynamics CRM on-premises? Sounds odd..

Recently I have faced an issue with SSRS reports and Dynamics CRM 2011 on-premises deployment (development ORG) wherein the reports were running well and fetching the expected data in BIDS solution but unable to show the data when I upload this report to Dynamics CRM. There were no errors as such but the report was blank, no data. Additionally, the report was fetching the data when you run a report on SSRS report server. Huh…

To resolve it I had rechecked the complete configuration of this report in BIDS as well as at Report Manager. I had uploaded another report and no luck with that as well. In fact none of my custom reports were able to fetch data.

After doing some search on net I found below thread,

http://social.microsoft.com/Forums/en/crm/thread/6521ee17-c2c9-4401-8a29-c7cde9d8ba24

As specified in this thread, I re-entered to Report Manager and at that time I saw that many reports are deployed and published by user like DOMAIN\MachineName$. Then I added the same person (DOMAIN\MachineName$) as a User in Dynamics CRM and this change had resolved the problem.

Did someone else ever face such issue before? If yes then please feel free to comment on this post with your understanding of the problem and resolution.

Friday 11 January 2013

Dynamics CRM 2011 On-premises – “CRMAF_” does not work for Custom SSRS reports

This is a small post. I hope this will help developers at least by saving a day.

To run a contextual custom SSRS report for Dynamics CRM 2011 on-premises, we need to give an alias with “CRMAF_” keyword to a Filtered View in our SQL query. For instance, you wish to run a custom SSRS report for an Account entity from an entity record, entity list area and reports area then provide an alias as shown in below query.

SELECT 
accountid
FROM
    FilteredAccount AS CRMAF_FilteredAccount


When you upload this a report with above query Dynamics CRM will replace the FROM table name with a sub-query parameter. To know more about “CRMAF_” magic please refer below URL.

http://msdn.microsoft.com/en-us/library/gg328288.aspx#SQLBasedPre_Filtering

In my case when I had uploaded a report using a simple query as specified above, Dynamics CRM did not replace it with a sub-query parameter on my development machine. I had also removed the report record from development machine more than once and re-imported it as afresh report with no luck. However the same RDL file was working well on another CRM on-premises server/machine. After some investigation I came to know that the problem is related to report data source connection string!!!

Below is the connection string that I had specified in my custom report data source properties.

image

Workaround

I had replaced the above connection string with some other server and database name and uploaded it again on development machine. Voila!! This change worked for me and was able to run my report contextually on my development machine.

Did anyone else face such problem? If yes then please feel free to share your understanding about the problem with the solution(s) as comments on this post.

Friday 4 January 2013

CRM 2011 Lookup functionality in a Silverlight Data Grid

In this post I will explain you how to create the CRM lookup control functionality in Silverlight data grid control. There will be a column of lookup data type that allows you to select related entity record as seen in bellow screenshot. Here in this example I am going to create a lookup column of an Account entity.

image

To implement the same look and feel of the lookup column, write the below given code in your xaml file of Silverlight application.

<sdk:DataGridTemplateColumn Width="190" Header ="Account" CellStyle="{StaticResource CRM2011_DataGridCellStyle}">
                <sdk:DataGridTemplateColumn.CellTemplate>
                  <DataTemplate>
                    <Border BorderThickness="1">
                      <StackPanel>
                        <StackPanel.Resources>
                          <Style x:Key="LookupHyperlinkStyle" TargetType="HyperlinkButton">
                            <Setter Property="FontFamily" Value="Fonts/segoeui.ttf#Segoe UI"/>                          
                            <Setter Property="Foreground" Value="Blue"/>
                            <Setter Property="FontSize" Value="11"/>
                            <Setter Property="BorderThickness" Value="1"/>
                            <Setter Property="VerticalAlignment" Value="Bottom"/>
                            <Setter Property="FontWeight" Value="Normal"/>
                            <Setter Property="Padding" Value="3,0,0,2"/>
                          </Style>
                        </StackPanel.Resources>
                        <Grid x:Name="lookupData" Background="White">
                          <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto"/>
                            <ColumnDefinition Width="150"/>
                            <ColumnDefinition Width="21"/>
                          </Grid.ColumnDefinitions>
                          <Image Source="{Binding Path=ink_AccountImageUrl}" Height="16" Width="16" Stretch="Fill" Grid.Column="0"></Image>
                          <HyperlinkButton  x:Name="LookupDataName"  Grid.Column="1" Click="LookupDataName_Click"  Style="{StaticResource LookupHyperlinkStyle}" >
                            <HyperlinkButton.Content>
                              <Binding  Mode="TwoWay" Path="ink_Account.Name"></Binding>
                            </HyperlinkButton.Content>
                          </HyperlinkButton>
                          <HyperlinkButton x:Name="OpenLookupData" Grid.Column="2" Click="OpenLookupData_Click" HorizontalAlignment="Right" >
                            <HyperlinkButton.Content>
                              <Image x:Name="ImgLookup" Source="/ExpenseNote;component/Images/LookupButton.png" MouseEnter="ImgLookup_MouseEnter"  MouseLeave="ImgLookup_MouseLeave"  Height="20" Width="21" Stretch="Fill"></Image>
                            </HyperlinkButton.Content>
                          </HyperlinkButton>
                        </Grid>
                      </StackPanel>
                      <Border.BorderBrush>
                        <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                          <GradientStop Color="Gray" Offset="0" />
                          <GradientStop Color="Gray" Offset="1" />
                          <GradientStop Color="Gray" Offset="0.105" />                        
                        </LinearGradientBrush>
                      </Border.BorderBrush>
                    </Border>
                  </DataTemplate>
                </sdk:DataGridTemplateColumn.CellTemplate>
              </sdk:DataGridTemplateColumn>


The column consists of mainly three controls:-

image

1) The image control to display account image. This is a web resource in Dynamics CRM.

2) The second control is a hyperlink button (in above example it is named as “LookupDataName”). Once you select a record from account lookup window, this link will help you to open the selected account record, same as we do in Dynamics CRM.

3) The third control is a hyperlink button (in above example it is named as “OpenLookupData”). This button will help you to open a popup window as shown in below screenshot.

image

Now let’s look into the code behind part of Silverlight control.

Below are the two methods that help you to toggle the images on mouse hover and mouse out for lookup hyperlink button (a third control).



private void ImgLookup_MouseLeave(object sender, MouseEventArgs e)
    {
      try
      {
        Uri uri = new Uri("/ExpenseNote;component/Images/LookupButton.png", UriKind.Relative);
        ImageSource imgSource = new BitmapImage(uri);
        ((Image)sender).Source = imgSource;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
 
    
 
    private void ImgLookup_MouseEnter(object sender, MouseEventArgs e)
    {
      try
      {
        Uri uri = new Uri("/ExpenseNote;component/Images/lookupbutton_hover.png", UriKind.Relative);
        ImageSource imgSource = new BitmapImage(uri);
        ((Image)sender).Source = imgSource;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }


Below is the method that will open lookup record window for an Account entity. Replace “_serverUrl” variable with your local variable. If you could see in below code, while opening lookupinfo.aspx page you are also allowed to specify other useful query string parameters like AllowFilterOff, DefaulType (Object Type), DidableQuickFind, DisableViewPicker etc. So, setup them based on your need.



/// <summary>  
    /// Opens account Lookup window 
    /// </summary>  
    private void OpenLookupData_Click(object sender, RoutedEventArgs e)
    {
      try
      {
        //Open Lookup for Account.
        lookUpAccount = _serverUrl + "/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultType=1&DisableQuickFind=0&DisableViewPicker=0&LookupStyle=single&ShowNewButton=1&ShowPropButton=1&browse=0&objecttypes=1";
        dynamic ReturnedParams = HtmlPage.Window.Invoke("showModalDialog", lookUpAccount, null, "dialogWidth:600px;dialogHeight:600px");
 
        if (ReturnedParams == null)
        {
          return;
        }
        else
        {
          //Set the selected account
          Guid AccountId = new Guid(ReturnedParams.items[0].id);
          var AccountName = ReturnedParams.items[0].name;
          TheMainViewModel.SelectedExpenseNote.ink_Account.Id = AccountId;
          TheMainViewModel.SelectedExpenseNote.ink_Account.Name = AccountName;
          TheMainViewModel.SelectedExpenseNote.ink_AccountImageUrl = "/ExpenseNote;component/Images/AccountImg.png";
        }
      }
      catch (Exception ex)
      {
 
        throw ex;
      }
    }

If you notice I have implemented MVVM pattern in above code. The MainViewModel is an object of view model class. Its properties are bound with lookup controls. So, we just need setup the account Id, account name and image URL properties of this class. Now, once you select an account record from the popup window, the selected record will be displayed in a grid as shown in below screenshot.

image


Lastly, you wish to open that account record when you click on “test” hyperlink button as seen in below screenshot.

image

For that we need to write below code to open a main.aspx of Dynamics CRM in a popup window using “HtmlPage.PopupWindow” method.



private void LookupDataName_Click(object sender, RoutedEventArgs e)
    {
      try
      {
        if (((ink_expensenote)(ExpenseNotesGrid.SelectedItem)).ink_Account.Id != null)
        {
          Guid lookupId = new Guid(((ink_expensenote)(ExpenseNotesGrid.SelectedItem)).ink_Account.Id.ToString());
          HyperlinkButton link = e.OriginalSource as HyperlinkButton;
          if (link != null)
          {
            HtmlPopupWindowOptions options = new HtmlPopupWindowOptions();
            options.Left = 0;
            options.Top = 0;
            options.Width = 800;
            options.Height = 600;
            options.Menubar = false;
            options.Toolbar = false;
            options.Location = false;
            options.Resizeable = true;
            options.Scrollbars = true;
            //Open a record in new window
            HtmlPage.PopupWindow(new Uri(_serverUrl + "/main.aspx?etc=1&extraqs=%3fetc%3d1%26id%3d%257b" + lookupId.ToString().ToUpper() + "%257d&pagetype=entityrecord"), "_blank", options);
          }
        }
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

I hope this post will be helpful to developers who want to have lookup type of column in Silverlight data grid control.