Monthly Archives: August 2017

Options sets and statuscode – doing some testing..

There were a few questions in the community forums lately related to some kind of inconsistency in how statuscode optionset behaves, so I figured I’d do a bit of testing tonight.

Here is the set up:

  • I created a new custom entity
  • Added two additional status reasons
  • And, also, added a new option set field

 

Here is how the form looks like:

image

I’m going to see how option set control methods work in different situations.

1. Test 1

I’m going to set statuscode and custom field value in the onload of the form:

image

Here is the result – everything’s good so far:

image

 

2. Test 2

I’m going to clear option statuscode and option set control options, then add them programmatically, then set field values:

image

Here is the result:

image

That’s exactly why those questions were asked – do you see how my custom field has a value, yet Status Reason is still empty?

3. Test 3

Let’s use the good old setTimeout and see if that changes anything

image

And here is the result now:

image

 

Cool, huh?

I actually have no idea why it’s like that, but I’m assuming there is something about statuscode that makes it different from all other option sets. Maybe it’s the state transitions:

https://msdn.microsoft.com/en-us/library/dn689032.aspx

I did not have any of those defined, though.

Maybe it’s the fact that statuscode is dependent on the statecode. Maybe both.

Either way, it seems that, unlike other option set controls/attributes, statuscode control needs a bit of time for the initialization once you have used those optionset-specific methods such as clearOptions, addOption, etc. You can give it that time by introducing a timeout which does not have to be that big at all, it just have to be there, and, after that timeout, statuscode is back in business.

Happy 365-ing!

I do quite a bit of development.. and yet I hate being called a Dynamics developer

Every day I come to work, and I open my Visual Studio to develop yet another plugin / javascript / SSIS package / SSRS report.. And, then, an email comes in from a user who does not know how to do “this and that” in Dynamics, and we talk, and we get back to what we had been doing before (although, either the user knows, now, how to do “this and that”, or I have a new feature request in my backlog). And, then, a project manager shows up and asks if everything is going according to the plan, and I explain that, apparently, not quite, though we may still be able to pull it off.. And, then, I create a workflow to do something quickly.. And a new custom entity.. And a bunch of new fields.. And I don’t normally do business rules – they really feel cumbersome more often than not.

But, with all that, I absolutely hate when somebody calls me a Dynamics developer. That I’m formally on the team that’s doing “development” does not make me a developer. In my mind, I’m a Dynamics Consultant, and, so, I can pick and choose the tools which fit best in every particular situation. Sometimes, it can be a workflow. Sometimes, it can be a plugin. And, quite frankly, I don’t care that much about what the Architect (if there is one on the project) is going to tell me since, more likely than not, we will have to discuss our options once I look into it anyway (but that’s why I prefer to be the Architect.. rather than to give that much authority to somebody else)

So.. This post is going to be much less technical than most of the other posts here, and, actually, it has a lot to do with the discussion Ben Hosking started recently:

image

The problem is right there..

Apparently, somehow there is a separation between “consultants” and “developers”. But, where I would agree that not every developer is, also, a Dynamics Consultant, I would really disagree with anyone telling me that you can be a Dynamics Consultant without knowing anything about the XRM capabilities.

However, if you know about those capabilities, you’ll be able to make a conscious choice when asked about the most appropriate technique to use in each particular situation.  That’s, basically, what makes you a Dynamics Consultant – your ability to advise the client what the options are. Of course, you might not be that strong on the technical side to develop a plugin from scratch.. But, as long as you understand the options, and as long as you can explain them to the client, you are a consultant.

So, getting back to that screenshot above, I do think that Dynamics Consultants are supposed to be able to choose which technique is best, and that includes development techniques as well. Some consultants might be better developers than others, but it does not mean that any consultant can completely ignore the “development” side of Dynamics.

The reason I hate being called a Dynamics developer is that it sort of pushes me into the corner. Developers are supposed to develop, that’s not my case at all. There is so much more I’m supposed to do on the Dynamics  projects – business analysis, solution design, software architecture, pure coding, users training, pure configuration, maintaining the server, opening support tickets with Microsoft, maintaining the backlog, providing support to the users.. this list can go on and on.

This so-called “Dynamics developer” role is really quite peculiar and there is so little difference there is from a consultant. If you are a .NET developer, your work is focused on the development. But, if you are a Dynamics developer, you have to understand the product first of all – otherwise, your opportunity plugins will be conflicting with the out of the box price calculations, your validation plugins will be missing some unusual scenarios, and so on. Once you get there, you suddenly become a consultant, and, at some point, you will find yourself saying “well, I think it should be done with a workflow.. or, wait, it would be even easier to just configure a parental relationship.. although, how about this OOB workaround?”. But, when it’s called a “developer” role, that sort of implies certain things about what the person is supposed to be doing, and this is where things can easily go wrong because of the incorrect expectations on both the client and the “developer” sides.

So, call me all you want, but don’t call me a developer.. despite all the development I do every day. Dynamics Consultant would be just fine by me, although, if it’s a Dynamics Solution Architect, it’s, probably, even better.. since that gives me a bit more “authority” in terms of making decisions.

How to: roll up without limitations

Rollup fields in Dynamics are great, they are very useful, they are there out of the box, and a lot has been written about them.

Although, if you wanted to start somewhere, the page below would give you all the details:

https://technet.microsoft.com/en-us/library/dn832162.aspx

That said, there is a bunch of things you can’t do with the rollups:

image

This list is rather long, so, if you’ve been using rollup fields on your Dynamics implementations, you have probably run into some of those limitations.

I would add two more that came up recently in the community forums:

–  You cannot use a rollup to calculate the number of notes associated with a particular case (it’s probably the same with any other entity – can’t rollup over notes). No way to select notes below:

image

– You cannot create rollup fields on some entities (for example, there is a “Characteristic” entity which, somehow, does not allow rollup fields). There is just no rollup option:

image

So when this happens, when we run into a limitation, what can we do?

  • We can develop a plugin
  • We can develop a custom workflow activity
  • We can use javascripts
  • And there are, probably, other options as well

 

I wanted to show you how to do it with TCS Tools, though, since I just updated that solution to better support all those rollup scenarios. In a nutshell, all you need to do to define a custom rollup is:

  • Create FetchXml to query the data
  • Create a workflow that will use that FetchXml to update a field

 

So, let’s say we wanted to get the number of notes per case.  In one the earlier posts, I already described how we can use “Lookup Setter” custom workflow activity to set a lookup value:

http://www.itaintboring.com/dynamics-crm/dynamics-crm-use-a-workflow-to-set-a-lookup/

In the most recent version of the TCS Tools, that custom workflow activity has been renamed to “Attribute Setter” to better reflect its capabilities.

Here is how I am going to use it to count those notes:

  • I will create a whole number field on the case entity (Notes Count)
  • I will create a Lookup Configuration record to define fetch xml which will use aggregation to get the count of notes per case
  • Then I will create a workflow on the case entity (a  “child” workflow) which will use “Attribute Setter” custom workflow activity in combination with the fetch xml defined above to calculate notes count and to set “Notes Count” field. This will be a background workflow
  • And, finally, I will create a workflow on the notes entity which will be triggered on create/on delete of the note records and which will be calling that workflow on the case entity as a child workflow. This will be a real-time workflow

 

Why do I need two workflows? Because I want to do those calculates “on delete” of the note records, too. But, if I make it a real-time workflow, it will run before note record is deleted. So the note being deleted will still be counted, and I don’t want that to happen.

And, btw, if you wanted to know more about FetchXml aggregations, I would suggest this link:

https://msdn.microsoft.com/en-us/library/gg309565.aspx

Let’s get ready:

1. I need a new attribute on the case entity

image

2. I need a lookup configuration record

image

Here is what all those attributes mean:

“Name”: just a name. I’ll use it when setting up the workflow later

“Fetch Result Attribute”: where the result will be once my fetch xml is executed

“Entity Attribute”: this is the name of the attribute where the result will be stored

“Update Direction”: Entity. I want to update case entity, not all the records which will be retrieved by that fetch xml

For your reference, here is my fetchxml:

<fetch distinct=’false’ mapping=’logical’ aggregate=’true’>
<entity name=’annotation’>
<attribute name=’annotationid’ aggregate=’count’ alias=’count’/>
<filter type=’and’>
<condition attribute=’objectid’ operator=’eq’ value=’#incidentid#’ />
</filter>
</entity>
</fetch>

Notice how I’m using #incidentid# there. This allows me to choose only those notes which are associated with the case for which my workflow will be running.

3. I need to create a workflow on the case entity

image

image

Again, that’s a child process workflow.. I’m using Attribute Setter workflow activity.. And I’ve set up that activity to use my Notes Count lookup configuration from step #2.

Almost there, but I still need to call that workflow somehow

4. I need a workflow on the note entity

In this workflow, I will check if that notes record is related to a case, and, if yes, it will start my child process workflow from step #3

image

And that’s it. It is time to roll up!

rollup

Happy 365-ing!

Dynamics and WordPress, the follow up

Not sure if you’ve seen my previous post on using WordPress with Dynamics – that was merely a beginner’s attempt to connect WordPress to Dynamics.. however, folks at AlexaCrm (those guys who developed the plugin) did see it, and, apparently, they figured they couldn’t leave it that waySmile

In particular, George Doubinski got in touch and suggested that I took a look at the demo site that’s using the plugin.

Well, I was pretty sure there is a lot more you can do with this plugin when I was writing the previous post.. It turned out we can probably do even more. But let’s have a look, should we?

1. Here is the user profile screen

image

All it takes to display this form in WordPress is:

image

 

2. Do you have any support cases? Here is your standard client-portal case management functionality..
See your cases, create a new one..

image
You would think this one should be much more complicated? Hmm..
image

3. Now let’s see if there were notes on the case

 

image

This is, actually, a little more complex:

image

 

Apparently, this plugin can do a lot. The obvious question is, then, if it’s comparable to the Customer Portals from Microsoft.

This is where it becomes really interesting because, I think, it’s a wrong question. The right question would be if WordPress, combined with this plugin, is comparable to the Customer Portals from Microsoft.

In both scenarios we have some level of integration with Dynamics. However, this seems to be one of those classic battles.. On the one side, there is WordPress with its huge following, long history, and lots of successful implementations which are not limited to Dynamics. On the other side, there is Microsoft with its very custom portal solution which is based completely on Dynamics, which is still new, and which, with the introduction of this plugin, still has to answer the question of why it’s actually better.. because it’s not the only Dynamics-integrated portal solution now.

From the site management/content management perspective, I have a feeling WordPress will beat Dynamics Customer Portals solution easily. But, then, how much integration is, really, needed between a web site and Dynamics to make Customer Portals a preferred solution?

Does it really have to be integrated to such an extent that content management is done completely in Dynamics? Does it even make sense to turn Dynamics into a site management tool? Or is it sufficient to simply provide integration on the forms/view level (have a look at those screenshots above again) and leave site management to the specialized applications/solutions?

Guess I’ll just leave it there for now.. But, either way, well done, AlexaCRM:)

PS. If you wanted to see documentation for this plugin, you’ll find it here: http://docs.alexacrm.com/wpcrm/

 

Unlocking “add new” on the subgrids for read-only records

Here is what recently came up in the community forums:

  • There is a contract line out of the box entity
  • There is a custom entity that has a lookup to the contract line
  • There is a subgrid for that custom entity on the contract line form

So why don’t we see “+” button next to the subgrid when the contract line is in one of the read-only states?

Interesting question, actually.. And I’m not sure it used to be the same in pre-365 versions of Dynamics.

However, this is where Ribbon Workbench can get us the answer quickly. Let’s do this

1. Create a solution in Dynamics

2. Add our custom entity to the solution (don’t need to add anything else)

3. Open XrmToolBox (http://xrmtoolbox.com)

4. And install “Ribbon Workbench” plugin from the store

5. Connect to the organization and open Ribbon Workbench

It will ask for the solution to download, so let’s pick the solution created above:

6. Once the solution has been downloaded, do this (step by step)

  • Make sure you have your child entity selected in the entity list
  • Then chose the button (#2) on the screenshot
  • Right click on the button and select “Customize Command” option

7. You’ll notice that the area below will reload..

And, in particular, there will be that Mscrm.EntityFormIsEnabled rule.. Which is the reason for all these problems.

That rule is basically saying that the parent form has to be active for the “add new” button to work.

What do we do next? Let’s delete the bugger..

7. Delete the rule

12. Hit “Publish” and wait for the confirmation (this may take a few minutes)

 

It’s time to go back to that contract line screen and hit F5 in the browser:

Here you go.. The miracle of Ribbon Workbench has saved us again!

 

 

 

Access Teams – why do we really need them?

What is the real difference between Access Teams and Owner Teams in Dynamics? Is it just that selection in the Team Type dropdown?

Maybe let’s start the other way around: what’s not different?

  • They are both represented by the same entity
  • We can add users to both types of teams
  • We can share records with both types of teams

So, if access and owner teams are that similar, why did Dynamics introduce Access teams at some point(there used to be Owner teams only in the past)?

This is where, if you have not read the following article yet, you probably should:

https://www.microsoft.com/en-us/download/details.aspx?id=45905

But I’ll try to provide a shorter version below.

The problem with the owner security is that there is a lot Dynamics has to look at to validate user’s permissions.

  • Every user will have security roles assigned to him/her directly
  • However, if a user has been added to a team, that user will inherit security roles from the team as well

Imagine what’s going to happen if there are 10 teams. Or, maybe, 100 teams. Or 1000.. Those security calculations can quickly become the one and only job Dynamics will be spending all server resources on.

There are two ways to make this situation better (other than to redesign the whole security model):

  • Create some sort of cache
  • Reduce the number of teams which have to be considered

And this is exactly what Dynamics is doing behind the scene. First of all, there is a security cache on the server. It’s calculated when the user logs in, and it stays there until it needs to be recalculated. There a few reasons why that kind of cache may have to be recalculated, but, essentially, it’s all about changing the set of security roles which the user has. For example:

  • A security role can be assigned to one of the teams where this user is a member
  • User’s membership in the teams can be updated

If that happens, security cache will be recalculated (and that will take a bit of time – you may notice a slowdown when navigating to another page in Dynamics at that moment). As far as security cache is concerned, that’s more or less how it works.

However, Dynamics is also reducing the number of teams that can affect that cache by introducing the Access Teams. Because, you see, you cannot assign security roles to the access teams. So there is no need to do anything with the security cache when such a team is created and the users are added to the team.

The way I see it, that’s the one and only reason why Access Teams were introduced in Dynamics. Otherwise, the system could just keep using Owner teams where it currently requires an access team. It becomes really critical when you start thinking about the team templates and “sharing” in general. For every team template, there can be one team per record in Dynamics. Imagine 10000 opportunities in the system, each having it’s own access team.. IF those were owner teams, it would be a very tough scenario for the security cache calculations. With the access teams, Dynamics can just ignore them when doing those calculations (yes, it still has to calculate access granted through sharing.. But, at least, it can safely assume those Access Teams won’t have any security roles).

So the difference is not, really, that we cannot assign security roles to the Access Teams.. or that we cannot use Owner Teams with the team templates.. those characteristics of the Access/Owner teams are there because of how these two types of teams are supposed to affect Dynamics performance. Owner Teams will affect the cache directly, so we should not be using them for sharing that much. Access teams can be completely ignored from the security cache calculations standpoint, so, if we want to use record sharing with teams, we should be using Access Teams for that.

 

 

New in V9: What’s that with Xrm.Page being deprecated?

Ever since Microsoft has published the “Important Changes Coming..” article that provides a very nice overview of what we should expect in the updated version of Dynamics, I could not stop wondering what does this mean:

With all the great reviews of this new release published on the web so far, I’ve never seen anyone asking a very basic question: so, what is going to happen to all the customizations which were supposed to be “supported” during the upgrades?

From the upgrade perspective, if you look at that screenshot above, you might think you just woke up to see your worst nightmare alive. Because if you have any client-side customizations at all, you’ll be most definitely using Xrm.Page.. which is now becoming deprecated.

So.. why don’t I speculate a little. And, if you have any specific details, please drop me a note, and I’ll update this post to reflect them.

1. What is a deprecated feature?

A deprecated feature is not, really, a feature that is immediately removed. More often than not, it’s a feature that’s not recommended for use anymore since it will be removed later. That’s my understanding, and, even though I can’t find a reference right now, I believe this is how Microsoft is treating “deprecated” features.

In other words, it seems we don’t need to worry about our javascript customizations stopping to work once V9 is here. On the other hand, we still have to start planning how are we going to deal with the removal of those deprecated features in the future.

2. What’s the story with the supported customizations vs unsupported customizations

From my standpoint, the difference between supported and unsupported customizations was, really, the corner stone in the foundation of all those business cases which we used to build in favor of using java script and / or plugins when we were talking to the clients.

If Xrm.Page is deprecated and meant for removal.. that’s going to be the last huge blow to that line of argumentation. There have been a few so far:

  • We had to recompile our C# code for new SDK assemblies when 365 came around
  • We had to switch from using ODATA / SOAP to using Web API on the client side (well, at least we had to start planning for the removal of the ODATA & SOAP endpoints)

In a way, that makes any javascript / plugin customization a potentially unsupported customization, so there is no certainty now. We are only working with the probabilities:

  • The probability of business rules stopping to work is, say, 5% (with the updated business rules designer, some features stopped to work, actually)
  • The probability of “supported” javascript stopping to work is, say, 10%
  • The probability of “supported” SDK stopping to work is, say, 10%
  • The probability of unsupported javascript stopping to work is, say, 30%

Etc.. See what I mean? It’s a shift of the paradigm – in terms of supported vs unsupported, nothing is certain anymore (and I mean nothing.. how about the whole Service Module being deprecated in v9? We could have guessed it would happen, eventualy, but still)

Another story has to be written now instead of that old one about supported vs unsupported – I’m not sure what the story is going to be.

But I got distracted..

3. What does Xrm.Page mean on that screenshot above?

That’s what I am really not sure about. It seems that the majority of those changes are focused on the “context”. Which is understandable – if you are in the context of the form, you have access to the form attributes. If you are in the context of the editable grid, you should have access to the grid attributes. However, how do you access form context from the ribbon button if there is no Xrm.Page? If there is an alternative global object that will allow that kind of access, then why not to keep Xrm.Page.. Besides, there are methods from the Xrm.Page namespace which are mentioned on the right side in that table (in other words, in the “replacement API” column):

In other words, it seems that, even though Xrm.Page is deprecated, some of the functionality is supposed to stay there.

I guess we’ll see what’s going to happen really soone, once V9 is here. But, like I said, if you have any more details for now, I’d really appreciate if you could drop me a note so I could share those details here.

CodeNow: creating a plugin for Dynamics in XrmToolBox

First of all, why would you need to build a plugin in the XrmToolBox? Isn’t it what the Visual Studio is for?

I think the answer is “yes and no”. See, if you are a developer and have all the tools.. you probably don’t need to read this post (other than out of curiosity). But, if you are a Dynamics administrator, or, maybe, you are a developer who just needs to create a plugin quickly while you are away from your work computer.. Whatever the reason is, if you do need to create a plugin for Dynamics, and if you don’t have Visual Studio installed, you can do it with the CodeNow plugin easily now.

Before you continue, you may want to get CodeNow plugin installed, so here is where you’ll find the instructions:

http://www.itaintboring.com/tcs-tools/code-now-plugin-for-xrmtoolbox/

Once you have it installed, the process looks like this:

  • Using XrmToolBox, you can build a plugin
  • And, then, you can use PluginRegistrationTool to register the plugin

For the plugin registration tool, you will find a detailed walkthrough here:

https://msdn.microsoft.com/en-us/library/gg309580.aspx

In this post, I’ll walk you through the steps required to compile a plugin in XrmToolBox.

Here we go:

1. Open XrmToolBox and load CodeNow plugin

2. Select “Plugin” checkbox

Once you have selected the checkbox, CodeNow will display sample plugin code. You can actually use “Compile” command to compile plugin dll at this point, but it won’t, really, be very functional yet.

However, that sample code has all the basic code you need to start with..

So, why don’t we create a plugin for the account entity that will ensure that nobody will set account name to “Test”

3. Here is the code we are going to add

  if(entity.Contains("name") && (string)entity["name"] == "Test")
                 throw new InvalidPluginExecutionException("Cannot use 'Test' for the account name");

   

4. It’s time to compile the plugin?

When you click “Compile”, the tool will ask you for the dll file name, so.. just choose the file name you want. “Test.dll” might be just fine:

5. Now you can use the PluginRegistrationTool to register the plugin

And the SDK step, of course:

6. And, now, let’s do a quick test. Let’s try to update the account’s name:

Worked out just as we planned!

 

Code Now plugin for XrmToolBox

Code Now plugin for XrmToolBox

Strictly speaking, it’s not part of TCS Tools. But, either way.. it’s kind of cool to be able to run C# code directly from XrmToolBox, especially when you need to do something quickly. You can do it with the Code Now plugin right now:

To install the plugin, just download it from the XrmToolBox plugin store

DISCLAIMER: You can use TCS Tools and Code Now plugin on your Dynamics projects – there are no strings attached. However, if you do so, that means you agree that the author (me) cannot be held responsible for any issues that may or may not occur in your environment due to the use of these tools.
If you there is an issue with the CodeNow plugin you wanted to get fixed, or if you have a suggestion to implement, drop me a message:

How to turn this poor one-liner into a nice multi-line notification?

If you happened to use Xrm.Page.ui.setFormNotification in your javascript customizations, you have probably noticed that it does not support line breaks. Try adding <BR/> tags into those notifications, and you’ll get something ugly.. like this:

Apparently, setFormNotification does not really respect all those html tags – instead, it just displays them as regular text.

So, how do we make it more like this:

Or, maybe, even like this:

It’s possible, but only if we start messing with HTML in those forms. Which, of course, is far not the best practice. However, even though it may not be the best practice, it may still save you quite a lot of time if it were a choice between implementing your own notification engine as compared to just implementing a quick unsupported customization in javascript on top of the out of the box notification functionality. That said.. Let’s see how you can turn those out of the box one-liners into the nice multi-line notifications.

You can always use F12 in google Chrome to see exactly what it’s all about; however, I’ll just save you some time and summarize the problem:

when Dynamics is displaying those notificaitons, it’s displaying them in the <span> HTML elements. However, while innerText has all the right HTML, innerHTML property has the same HTML in the escaped form. So, for example, it’s using &gt, &lt in place of > and <)

Really all we need to do is this:

span.innerHTML = span.innerText;

We just need to find those span elements, and we need to run that code at the right moment.

Here is a function which will reset innerHTML – technically, you can add this function to a web resource, attach that web resource to your form, and, then, keep calling it after every call to setFormNotificaiton or clearNotification.

ResetNotificationInnerHTML: function () {
        debugger;
        var notificationsElement = parent.document.getElementById('crmNotifications');
        if (typeof notificationsElement != 'undefined' && notificationsElement != null) {
            var notificationSpans = notificationsElement.getElementsByTagName('span');
            for (var i = 0; i < notificationSpans.length; i++) {
                var span = notificationSpans[i];
                if (span.innerText != span.innerHTML) {
                    span.innerHTML = span.innerText;
                }
            }
        }
    }

We can take it a bit further, though. Can we make it work in such a way that any call to the Xrm.Page.ui.setFormNotification (or clearNotification) would automatically call ResetNotificationInnerHTML, too?

That’s where we can update the Xrm itself.


UpdateXrm: function () {

        Xrm.Page.ui.constructor.prototype.originalSetFormNotification = Xrm.Page.ui.constructor.prototype.setFormNotification;
        Xrm.Page.ui.constructor.prototype.originalClearFormNotification = Xrm.Page.ui.constructor.prototype.clearFormNotification;

        Xrm.Page.ui.constructor.prototype.setFormNotification = function (message, level, uniqueId) {
            this.originalSetFormNotification(message, level, uniqueId);
            ResetNotificationInnerHTML();
        };

        Xrm.Page.ui.constructor.prototype.clearFormNotification = function (uniqueId) {
            this.originalClearFormNotificationuniqueId(uniqueId);
            ResetNotificationInnerHTML();
        };

        ResetNotificationInnerHTML();

    }

That function above will add originalSetFormNotification and originalClearFormNotification to the Xrm.Page.ui, and it will store original setFormNotification and clearFormNotification in those two new methods.

Then it will replace those original setFormNotificaiton and clearFormNotification methods in such a way that they will now be calling ResetNoficiationInnerHTML, too.

So, now, you can simply call UpdateXrm() somewhere in the onLoad of your form.. and, then, you can keep using Xrm.Page.ui.setFormNotification as usual. Except that you will be able to use html tags in your notifications now.

I have added these scripts to the same javascript library that you can use to configure tabs, sections, and fields on the forms – have a look at this post for the details

If you wanted to try that library, make sure you have deployed updated version of the TCS Tools solution

Then, add tcs_/scripts/FormSupport.js web resource to your form. Once it’s there, you can simply add the following onLoad event handler:

TCS.FormSupport.UpdateXrm

It’s the same UpdateXrm function that I talked about a bit earlier in this post.. it’s just part of the library now.

That’s it – you should be able to create multi-line notifications. And, if you are feeling a little adventurous, you can actually add other HTML tags to the notifications. For example, how about adding a link:

Xrm.Page.ui.setFormNotification(“<a href=’http://itaintboring.com’ target=’_blank’>It Ain’t Boring</a>”, “INFO”, “3”);

 

Have fun!