Tag Archives: Preview

Dynamics 365 Solution Checker Preview available

The PowerApps team has released a preview of the Solution Checker which allows you to inspect your solutions against a set of best practice rules related to customising and extending the CDS for Apps platform.

The benefits provided include detailed reports listing issues identified, the severity, location and in some cases the line of code to improve. The result set also includes detailed prescriptive guidance on how to resolve or improve the issues.


For now you need to install the solution into your environment from the PowerApps Solution list by choosing to Install. This will take you to AppSource where you can review and install the feature.

The prescriptive documentation is presented from within the online PowerApps Documentation Best Practices site which is being continuously updated with new content.


CRM 2011 Grid with Preview Form

A sample of this html file can be downloaded from my Skydrive here http://sdrv.ms/RbwsKr



This week I was asked about showing an associated grid view and preview form within a Silverlight application similar to the way Outlook has a grid/preview layout. There are a couple of ways to do this and the one most obvious is to use the Silverlight controls and simply bind the CRM data to them. One alternative I pondered was to reuse the existing CRM Grid and CRM Form in IFrames on a HTML Page. This page could then be loaded into CRM as a Web Resource and opened by a Silverlight application or linked to in SiteMap, etc…

The main advantage to this approach is that any changes to the CRM form fields or grid columns would not require any change to be implemented to this html page, where as using a full Silverlight app you would have to update the application aswell. I’m going to show you the pieces of the prototype I built and hopefully you may be able to take this further for your own benefit. Here is a screenshot of the layout of the html page.

The html body consists of 2 iframes, one for the grid and the other for the form. In this example the grid is loading the Contact’s Activities associated grid view.

<body onload="Initialise()">


I have a number of constants for this prototype demo but some of these you will want to determine from a querystring or ClientGlobalContext.js.aspx file,

// You should collect the the server address and org values using the ClientGlobalContext.js.aspx file <a href="http://msdn.microsoft.com/en-us/library/gg328541.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/gg328541.aspx</a>
var server = "http://crm:5555"; // server url with port, if port required
var orgName = "Playground";

//  grid related settings
var entityId = "<A Guid Value goes here>"; // e.g. 00000000-0000-0000-0000-00000000000
var entityType = "2"; // Entity type for Contact
var areaView = "areaActivities"; // Activities associated view id found in Left hand Nav Pane by viewing DOM
//var areaView = "areaOpps"; // Opportunities associated view id found in Left hand Nav Pane by viewing DOM
var internalGridElement = "crmGrid_Contact_ActivityPointers"; // Activity Grid found in DOM
//var internalGridElement = "crmGrid_opportunity_customer_contacts"; // Opportunity Grid found in DOM

The body onload simply calls Initialise which sets the uxGrid iframe.

// Initialise page, set grid iframe
function Initialise() {
    document.getElementById("uxGrid").src = server + "/" + orgName + "/userdefined/areas.aspx?oId=%7b" + entityId + "%7d&oType=" + entityType + "&security=000000&tabSet=" + areaView;

When the grid loaded and when I selected a new view on the grid I received the ‘Error on Page’ and after tracing through the script I found that I could simply provide some stubs which handle the calls executed by the grid. I return null and I haven’t seen any functional issues arise from this during my testing.

// Stubs to handle grid in an IFRAME, errors occur otherwise
var Mscrm = new Object();
Mscrm.PageManager = new Object();
Mscrm.PageManager.get_instance = function() { return null; }

var crmRibbonManager = null;

$find = function(e) {
    return null;
// End Stubs

The following functions provide the functionality for the form preview to load. LoadPreviewPane is called when you single click a row in the grid. CleanFormWindow removes the form ribbon, left hand nav pane, footer and also disables all fields on the form.

// Show form in preview area
function LoadPreviewPane(entity) {
if (entity != null) {
document.getElementById("uxPreview").style.visibility = "hidden";
document.getElementById("uxPreview").src = server + "/" + orgName + "/main.aspx?etn=" + entity.TypeName + "&extraqs=" + escape("&id=" + entity.Id) + "&pagetype=entityrecord";
else {
document.getElementById("uxPreview").src = "about:blank";

// Remove chrome from around form in preview area
function CleanFormWindow() {
    if (event.srcElement.readyState == "complete") {
        var frameDoc = document.getElementById("uxPreview").contentWindow.document;

        if (frameDoc && frameDoc.getElementById("contentIFrame")) {
if(frameDoc.getElementById("perceivedRibbonId")) frameDoc.getElementById("perceivedRibbonId").style.display = "none";
frameDoc.getElementById("crmTopBar").style.display = "none";
 frameDoc.getElementById("crmContentPanel").style.top = "0px"; // Move Form Content area up to top of window, initial style.top is 135px
 frameDoc.getElementById("crmContentPanel").style.height = "100%";
 frameDoc.getElementById("contentIFrame").style.height = "100%";

 frameDoc.getElementById("contentIFrame").onreadystatechange = function() {

 if (frameDoc.getElementById("contentIFrame").readyState == "complete") {
 try {
 // Hide Left Hand Nav bar / pane
 frameDoc.getElementById("contentIFrame").contentWindow.document.getElementById("crmNavBar").parentElement.style.display = "none";
 frameDoc.getElementById("contentIFrame").contentWindow.document.getElementById("tdAreas").parentElement.parentElement.parentElement.parentElement.colSpan = 2;
 frameDoc.getElementById("contentIFrame").contentWindow.document.getElementById("tdAreas").parentElement.parentElement.parentElement.parentElement.style.height = "100%";

 // Hide the Breadcrumb and Record Set Toolbar
 frameDoc.getElementById("contentIFrame").contentWindow.document.getElementById("recordSetToolBar").parentElement.style.display = "none";

 // Hide the Form Footer Bar
 frameDoc.getElementById("contentIFrame").contentWindow.document.getElementById("crmFormFooter").parentElement.style.display = "none";

 // make everything readonly on the form using Xrm.Page controls

 // Everything is finished so show the form
 document.getElementById("uxPreview").style.visibility = "visible";
 } catch (ex)
 { }

// Delegate function for disabling control in form control collection
function SetControlDisabled(control,index)

The AttachGridEvent function attaches the GridClick function to the onselectionchange event of the internalGridElement defined in the constants earlier. A line of code sets the grid to single row selection to prevent a user from selecting multiple rows.

function AttachGridEvent() {

if (document.getElementById("uxGrid").readyState == "complete") {
var frameDoc = document.getElementById("uxGrid").contentWindow.document;
if (frameDoc.getElementById(internalGridElement) != null) {
frameDoc.getElementById(internalGridElement).attachEvent("onselectionchange", GridClick);
// Set grid to single select
frameDoc.getElementById(internalGridElement).document.getElementById("max").value = 1;
// GridClick function for onselectionChanged event
var bFired = false;
function GridClick() {
selectedItems = new Array();

var grid = null;

//    get array of selected records
var frameDoc = document.getElementById("uxGrid").contentWindow.document;

if (bFired == false) {

if (frameDoc.getElementById(internalGridElement)) {
grid = frameDoc.getElementById(internalGridElement).control;
if (grid.get_selectedRecordCount() > 0) {
var records = grid.get_selectedRecords();
// record object fields
// Id
// Name
// TypeCode
// TypeName
else {
bFired = true;
else {
bFired = false;

Hopefully you are able to reconstruct a html page from these examples and remember you must import the html page as a Web Resource otherwise you will end up with a cross domain error.