Friday, 27 July 2012

CRM 2011–Managed Solution–Transport Gotchas


Today, I would like to share some gotchas of managed solution while transporting the customization changes on another organization:

1. You cannot activate/deactivate the views and transport the same status on production server via overwriting the managed solution.

2. You cannot setup default public view and transport the same status on production server via overwriting the managed solution.

3. Similarly, you cannot setup default dashboard and transport the same status on production server via overwriting the managed solution.

4. To expand or collapse tabs on forms, like you cannot expand Notes & Activities tab although you tick “Expand this tab by default” on entity form.
In a same manner, you cannot collapse the tabs like General, Notes & Activities etc. although you unchecked “Expand this tab by default”.

5. Start Auditing on any of your entities is not being transported on production server.

The above points are in my knowledge. Please feel free to append this list with your experiences as well.

Thursday, 19 July 2012

Dynamics CRM 2011 - Odd behaviour of Product default lookup view on Order Product record

Yesterday, I faced a weird behaviour of order product entity on production server & in fact did not visualize the same during development phase. This is related to a default lookup view of existing product on Order Product entity record.

In Dynamics CRM a default lookup view for this entity is “Products in Parent Price List”. Means you will only be allowed to select the products of Price List that was selected on Order record (Parent record). On yesterday I found that the default view was changed to “Product Lookup View” and it now allows you to select products of all Price Lists. Weird….

After goggling for an hour I came to know that this is because I wrote some JavaScript code on change event of this lookup field to do some calculation of pricing based on product selection. So when you write custom code on the OnChange event of such "special" lookups CRM loses its normal behaviour.

Workaround

  • Create a new temporary unmanaged solution on development organization.
  • Add an Order Product entity to this solution.
  • Export this solution as unmanaged.
  • Unzip the customization files.
  • · In customiztaion.xml, change the default view GUID back to “Products in Parent Price List” ({BCC509EE-1444-4A95-AED2-128EFD85FFD5}) by replacing the current GUID of “Product Lookup” ({{8BA625B2-6A2A-4735-BAB2-0C74AE8442A4}}).
  • Import the solution back to the development organization & publish the changes.
  • You can now validate the default lookup view for Product lookup.
  • Now, export your original unmanaged solution as Managed to be imported on production server.

Referred links

http://social.msdn.microsoft.com/Forums/en-US/crm/thread/5eac1b84-ca66-41ba-9da7-06bbc49ffdad#e6908e92-e5a5-4d57-bc54-2fcaf393b7e2 

http://blogs.msdn.com/b/apurvghai/archive/2012/02/15/exisitng-product-lookup-lists-all-the-products.aspx

Friday, 13 July 2012

Applying Dynamics CRM 2011 styles to a Silverlight application

In this post we will discuss how we can apply CRM styles to different Silverlight controls like button and datagrid.

First we will have a look how to apply styles in Silverlight application.

For styling a Silverlight application we cannot use CSS which is mostly used for styling web applications. Silverlight offers two styling method implicit styling and explicit styling.

In Implicit styling you can specify the style as given below:-
<Style TargetType="Button">
    <Setter Property="Background" Value="Green"/>
    <Setter Property="Foreground" Value="Blue"/>
    <Setter Property="FontSize" Value="11"/>                          
</Style>
Style attribute is not specified with the control when using the implicit style

<Button  x:Name="GreenButton" Content="Green Button"/> 
In Explicit styling the style is specified as :-

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Green"/>
         <Setter Property="Foreground" Value="Blue"/>
    <Setter Property="FontSize" Value="11"/>                          
</Style>
To implement explicit styling the style attribute is specified

<Button x:Name=" GreenButton" Content="Green Button" Style="{StaticResource ButtonStyle}"/>
The implicit styling can be overwritten by specifying explicit style in the control.

In this post we will see how we can define explicit styles.

Create a folder that will contain xaml pages used for designing. Each page having explicit style defined for different controls.

Create a page CRM2011_ButtonStyle.xaml and specify the button style as specified below :

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style x:Key="CRM2011_ButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="#FF1F3B53"/>
    <Setter Property="Foreground" Value="#FF000000"/>
    <Setter Property="Padding" Value="3"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush" Value="#FF666666" />
    <Setter Property="Height" Value="22" />
    <Setter Property="Width" Value="84" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid>
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                  <Storyboard>
                    <ColorAnimation Duration="0" To="#FF336699" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="Background"/>
                    <ColorAnimation Duration="0" To="#FFE2F1F9" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FFC4E5F6" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FF98D1EF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FF6CB4DB" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed">
                  <Storyboard>
                    <ColorAnimation Duration="0" To="#FF000000" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="Background"/>
                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/>
                    <ColorAnimation Duration="0" To="#FFE2F1F9" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FFC4E5F6" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FF98D1EF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                    <ColorAnimation Duration="0" To="#FF6CB4DB" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="Disabled">
                  <Storyboard>
                    <DoubleAnimation Duration="0" To=".45" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualElement"/>
                  </Storyboard>
                </VisualState>
              </VisualStateGroup>
              <VisualStateGroup x:Name="FocusStates">
                <VisualState x:Name="Focused"/>
                <VisualState x:Name="Unfocused"/>
              </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="#FFD4D0C8">
              <Grid Background="{TemplateBinding Background}" Margin="1">
                <Border x:Name="BackgroundAnimation" Background="#FF448DCA"/>
                <Rectangle x:Name="BackgroundGradient">
                  <Rectangle.Fill>
                    <LinearGradientBrush StartPoint=".5,0" EndPoint=".5,1">
                      <GradientStop Color="#FFF2F2F2" Offset="0"/>
                      <GradientStop Color="#FFECECEC" Offset=".5"/>
                      <GradientStop Color="#FFDDDDDD" Offset=".5"/>
                      <GradientStop Color="#FFD3D3D3" Offset="1"/>
                    </LinearGradientBrush>
                  </Rectangle.Fill>
                </Rectangle>
                <Border BorderBrush="#FFFFFFFF" BorderThickness="0,1,0,0" />
              </Grid>
            </Border>
            <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            <Rectangle x:Name="DisabledVisualElement" Fill="#FFFFFFFF" IsHitTestVisible="false" Opacity="0"/>
            <Rectangle x:Name="FocusVisualElement" IsHitTestVisible="false" Margin="1" Opacity="0" Stroke="#FF666666" StrokeThickness="1"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
  <!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>
Notice that the style is mentioned within a ResourceDictionary. Silverlight styles are implemented using a mechanism called ResourceDictionaries. ResourceDictionaries can be merged, so we can define styles in several places and merge them into a single dictionary. Unfortunately this is necessary for applying several style definitions to the same control.
Merging Resource Dictionary

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="CRM2011_ButtonStyle.xaml"/>
        <ResourceDictionary Source="CRM2011_DataGridStyle.xaml"/>
        <ResourceDictionary Source="CRM2011_ScrollBarStyle.xaml"/>
        <ResourceDictionary Source="CRM2011_DataGridColumnHeaderStyle.xaml"/>
        <ResourceDictionary Source="CRM2011_DataGridCellStyle.xaml"/>
        <ResourceDictionary Source="CRM2011_DataGridRowStyle.xaml"/>        
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
You can find a Silverlight application with CRM style Datagrid at http://www.devvblog.com/?p=58

Friday, 6 July 2012

Dynamics CRM 2011– Some JavaScript Tips


How to check form mode using Javascript?

Xrm.Page.ui.getFormType() function returns the form type or form mode. Using this function you can make out if the form is currently opened in edit mode or create mode
//Create mode
if (Xrm.Page.ui.getFormType() == 1) {
    //Do this
}
 
//Edit Mode
if (Xrm.Page.ui.getFormType() == 2) {
    // Do this
}

How to get Parent Entity Id when a form is in create mode?

When you add a new record from subgrid of an entity and you need the Parent Entity Id which is the Id of the record from which the child form is created ,you can get it from the query string.

//Create mode
if (Xrm.Page.ui.getFormType() == 1) {
 
    var qs = new Querystring();
    var Id = qs.get("_CreateFromId", "");
}

How to set Lookups attributes?

//Using the code in below line you can set the lookup for entity of type 2 i.e. Contacts only
document.getElementById("to").setAttribute("lookuptypes", "2");
 
//Using the code below you can set the default lookup type to Contacts
document.getElementById("to").setAttribute("defaulttype", "2");

The difference in the above two is that the first would restrict the lookup to Contacts only whereas the second would set the default lookup type as Contacts but would not restrict the lookup to Contacts.

//Using the code below you can restrict the user for single value selection
document.getElementById("to").setAttribute("lookupstyle", "single");
 
//You can set the icons for selected lookup value using the code below
document.getElementById("to").setAttribute("lookuptypeIcons", "/_imgs/ico_16_2.gif");

How to implement window.open functionality in Outlook?

When you use window.open to popup a new window programmatically, it works fine with web application of CRM. But when you execute it in Outlook the new window will open as an IE window and a Sign In page is displayed. So to open it in Outlook like any other outlook window you can use the function “openStdWin”.

openStdWin("Url", "_blank", width, height, features);

How to implement Oncheck event of checkbox?

When you click on a checkbox the onclick/oncheck event is not fired until the checkbox loses focus. To solve this issue and implement oncheck event immediately after the checkbox is checked or unchecked attach the following function on the onload event of the form and this will fire the onclick event.

// fire Oncheck event of checkbox
function CheckboxOnLoad() {
    crmForm.all.ink_applyvat.onclick = function () {
        crmForm.all.ink_applyvat.FireOnChange();
    };
}
How to reload a parent form OnRefresh of a subgrid?

To reload a form OnRefresh event of its subgrid attach the following function to the onLoad event of the form

//Reload parent form to reflect changes from related subgrid entity
var interval = null;
 
function OrderLoad() {
    interval = setInterval("SubGridRefresh();", 15000);
}
 
function SubGridRefresh() {
    var grid = document.getElementById("OrderProducts");
    if (grid) {
        grid.attachEvent("onrefresh", ReLoadForm);
        if (interval != null) {
            clearInterval(interval);
        }
    }
}
 
function ReLoadForm() {
    window.location.reload(true);
}

The function SubGridRefresh attaches the function ReLoadForm with the OnRefresh event of Subgrid. SubGridRefresh is called after some delay because at the time of OnLoad event the subgrid may or may not have loaded so the event handler cannot be attached in case it is not loaded. So the setInterval function will keep on calling the SubGridRefresh function till the Subgrid is loaded and the event handler is attached.