Blog

Custom Dialog Boxes - Part 1

– 8 Minutes

Back in July 2017, Microsoft deprecated the dialog process, and announced that they would be replaced with task flows. While I think task flows are great, they only let you interact with fields on a single entity. If you want to do something more advanced like working with fields from multiple entities or interfacing with data from an external web service, you cannot.

Another problem with task flows is that you are forced to use the layout that Microsoft defines. You will see the fields in a linear order, and you cannot tailor the layout to how your users want to see it. While this may be acceptable for most users, it can result in a less than optimal user experience.

What can we do about this?

If you've looked at the solution explorer recently, you may have noticed a "Dialog Boxes" component. What is a Dialog Box, you ask? They are essentially system forms with custom controls that are shown in various parts of the application. For example, the Import Wizard dialog opens pinned to the right side of the screen and lets users import data, and the Switch Process dialog opens in the center of the screen and lets users switch the Business Process Flow on the record. The system Dialog Boxes all use custom controls -- which is the real power of Dialog Boxes, they use controls from the Custom Control Framework which allows for a custom tailored user experience. Wouldn't it be great if we could create our own? Unfortunately there is no simple way of doing this. But...I think you know where the rest of this blog is going...

The real power of Dialog Boxes is that they use controls from the Custom Control Framework which allows for a custom tailored user experience.

I believe that what I will show below is technically supported per Microsoft's documentation. We are allowed to unpack, modify Form XML of forms, and repack solutions. And as I mentioned above, a Dialog Box is nothing more than a system form.

To get started, let's create a blank solution and export it. This will give us our empty solution.xml and customizations.xml. First, let's add a Dialogs element in our customizations.xml file. This is a new node that lets us define system forms that are not associated with an entity and can be used in a custom dialog.

<ImportExportXml>
  <Dialogs>
    <Dialog>
      <IsCustomizable>1</IsCustomizable>
      <IsTabletEnabled>1</IsTabletEnabled>
      <CanBeDeleted>1</CanBeDeleted>
      <IntroducedVersion>1.0.0.0</IntroducedVersion>
      <UniqueName>CustomDialog</UniqueName>
      <LocalizedNames>
        <LocalizedName description="Custom Dialog" languagecode="1033" />
      </LocalizedNames>
      <Descriptions>
        <Description description="Shows the custom dialog process." languagecode="1033" />
      </Descriptions>
      <FormId>{22222222-2222-2222-2222-222222222222}</FormId>
      <FormXml>
        ...
      </FormXml>
    </Dialog>
  </Dialogs>
</ImportExportXml>

If you're familiar with how entity forms are saved in the customizations.xml file, this should look fairly familiar. The major difference is that we're under the Dialogs node instead of the Entities node. Remember the UniqueName as we'll use it later.

Next, we need to define the XML for the form. We'll put this inside the FormXml tag:

<forms>
  <form>
    <header id="{20A88883-CFD3-49AC-A0AC-7A5A5916B494}">
      <rows>
        <row>
          <cell id="{B65D2006-F3EF-4A95-BAAC-AAA10F4CB370}">
            <labels>
              <label description="Custom Dialog" languagecode="1033" />
            </labels>
            <control id="FormHeader" classid="{39354e4a-5015-4d74-8031-ea9eb73a1322}" isunbound="true">
              <parameters>
                <IsTitle>true</IsTitle>
              </parameters>
            </control>
          </cell>
        </row>
      </rows>
    </header>
    <tabs>
      <tab id="{4096ED0D-B54B-4A90-8E14-6DE2F97EE1DF}" verticallayout="true" name="Tab">
        <labels>
          <label description="This is a tab." languagecode="1033" />
        </labels>
        <tabfooter id="{303f1bb7-3f05-423b-8b27-135b552b8375}">
          <rows>
            <row>
              <cell id="{7B9024DA-67E3-48F6-A29D-90675D51A66D}">
                <labels>
                  <label description="Close" languagecode="1033" />
                </labels>
                <control id="tab1footerclose" classid="{00ad73da-bd4d-49c6-88a8-2f4f4cad4a20}" isunbound="true" />
              </cell>
              <cell id="{de13da57-74b4-4242-aab0-d320672db84d}">
                <labels>
                  <label description="Next" languagecode="1033" />
                </labels>
                <control id="tab1footernext" classid="{00ad73da-bd4d-49c6-88a8-2f4f4cad4a20}" isunbound="true" />
              </cell>
            </row>
          </rows>
        </tabfooter>
        <columns>
          <column width="100%">
            <sections>
              <section id="{EB813F55-D4A8-4A95-AF10-162655D9FB91}" showbar="false" columns="1" name="Section">
                <labels>
                  <label description="This is a section." languagecode="1033" />
                </labels>
                <rows>
                  <row>
                    <cell id="{28AB7101-C235-4DEF-A3A9-5B3915AE153B}">
                      <labels>
                        <label description="Name" languagecode="1033" />
                      </labels>
                      <control id="name" classid="{4273EDBD-AC1D-40d3-9FB2-095C621B552D}" isunbound="true" disabled="false" uniqueid="{902702AE-B334-4603-9D7B-EFB2F49D4408}" />
                    </cell>
                  </row>
                </rows>
              </section>
            </sections>
          </column>
        </columns>
      </tab>
    </tabs>
  </form>
</forms>

Again, this should look fairly similar to an entity form. There are some differences, however. For example, there is a tabfooter node which is where we can put things like the Close or Next buttons.

That's all we need, for now, with the customizations.xml file updated. We can now add a reference to the form in the solution.xml file.

<ImportExportXml ...>
  <SolutionManifest>
    ....
    <RootComponents>
      <RootComponent type="60" id="{22222222-2222-2222-2222-222222222222}" />
    </RootComponents>
    ...
  </SolutionManifest>
</ImportExportXml>

Notice that the ID of the RootComponent is the same as the FormId of the Dialog. With the solution.xml updated, we can zip our solution back up and import it into our Dynamics 365 environment! After the import succeeds, you can open up the solution and see that it created the custom Dialog Box component!

With the Dialog Box successfully created, how do we use it? It's actually surprisingly simple! From the Unified Interface, we can just call a JavaScript function. The first argument is the UniqueName of the form we created in the customizations.xml file.

Xrm.Navigation.openDialog("CustomDialog", { position: 1 });

This function is in the Xrm.Navigation namespace which has several other documented functions (openConfirmDialog, openAlertDialog, etc.), however openDialog is not (yet) documented. Personally, I would consider it supported...at the very least, it's better than using something in the Xrm.Internal namespace!

Setting a position of 1 will open it in the center of the screen as shown above. We could also set a position of 2 to tether it to the right side of the screen, like so.

Heck, we could even put a position of 3 which will open it up in "inline" mode!

That's all there is to it! This opens the door to creating highly customized dialog windows, and will provide a fully supported method for creating modal dialogs!

This is the first post in this series. In the next few, I will cover topics including using multiple tabs/pages, adding custom controls to the form, adding onload/onclick event handlers, and updating fields on the form.

Stay tuned!

Comments

Scott Durow

An awesome glimps of what’s in store - this is still a preview and isn’t supported in production yet.

Syed Hanifa

Excellent bro..added one more line item to your creativity..keep rocking.

ashutosh

Great work

Mauro Masucci

Are you sure this functionality isn't going to be removed too? Can we run Business Rules against these forms?

Ben Thompson

@Mauro, the only thing that may not be supported is the use of Xrm.Navigation.openDialog when Xrm.Navigation.Form (see https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-navigation/openform ) seems to provide much the same functionality albeit without the next button....

Vipin

Nice article Bob :)
I need few suggestion and guidance from you.

As these dialog are like pop-up, blocking CRM in background and unless user finishes up with dialog he cannot do anything in the CRM.

Can we have something as overlay pop-up or banner.

My original requirement is something where, I need to display a term and condition banner on the MS CRM, when someone logs into dynamic CRM. User may accept or reject terms or condition, but this banner is OVERLAY and user still can scroll and operates in CRM.

The challenge here is, I need to display such thing when a user logs into CRM, being every user may have different login screen or page.

Can someone think of how can we fulfil this particular requirement.

Andreas Cieslik

I assume this works with classic forms as well?

SHRTUTI

how to add the other extra fields because if any extra field then it is not importing . Can you guys help me to do it in dialog Box

PMP

Unfortunately, I can't seem to import it due to the 'Dialogs' element.

The element 'ImportExportXml' has invalid child element 'Dialogs'. List of possible elements expected: 'GlobalSearchConfigurations, StoredProcedures'.