VS2010 Launch – The Big Tease

First off for anyone who thinks this is a post to bash Microsoft, you’re reading the wrong blog.

So what’s this about? It’s a little about VS2010, a little about bad design, and a little about JavaScript. Ready? Good.

Alrighty then, today’s the big day when a few products were launched. Nothing big, just most of Microsoft’s developer toolset. Let’s see, there’s:

  • .NET Framework 4
  • ASP.NET 4
  • Silverlight 4
  • Visual Studio 2010

ASP.NET MVC 2 released about a month ago, but those guys are a little off, right Phil?

But I digress. The main lead-up to this was a launch event that is happening in several places around the world and perhaps most notably in Las Vegas in conjunction with DevConnections. Go to Microsoft’s website more than an hour before the keynote and you were presented with a countdown timer to help build the suspense. I for one was in suspense. I had held my laptop in a pristine state since I didn’t want to worry about any hassles associated with previously installed betas or release candidates. So I watched the countdown go to 0, and nothing happened. OK, I’ve seen this happen before and I know how conferences go, so I check back every 5 minutes or so. 5 minutes later, nothing. 10 minutes later, nothing. 45 minutes later, nothing! What the heck?

The final countdown!
Biggest. Tease. Ever.

How could I be watching this timer for over an hour and not the keynote? About then my brain kicked in where someone else’s didn’t. Since this thing was straight HTML and not Silverlight or Flash, I decided to view the page source and see if my suspicions were right. Now, I had the page source ready to show you, but unfortunately my browser crashed while watching the keynote (ironic, I know), so I lost that. However, the gist of it is this. Whoever made this page decided to embrace jQuery (smart move #1) and avoid writing some ad-hoc code when something else existed (smart move #2). Unfortunately that’s where Smart Move Rd. intersected with Not Quite Blvd.

The code that they chose to make use of was a simple jQuery plugin to count down the time left until a specified date. The JavaScript/jQuery code (per Keith Wood’s site and my memory) was setup something like this:

var keynoteTime = new Date();
keynoteTime = new Date("April 12, 2010 08:30:00");
$('#countdown').countdown({until: keynoteTime});

That seems straightforward enough, doesn’t it? Of course it does, and it is. This plugin is great for certain uses, there was just one little detail that they didn’t consider. You see, the conference was in Las Vegas and I’m in Florida. JavaScript is a client side technology, and my client was on Eastern Time Zone time, hours ahead of Las Vegas time. So, I would have been staring a “0 hours, 0 minutes, 0 seconds” for another 3 hours before finally viewing the launch webcast. It sounded like a great idea at the beginning though, didn’t it? Oh well, I only had to wait another 5 hours to have Akamai serve me the VS2010 bits, but I’ve got ’em!

NOTE: I don’t know for sure that the code used was Keith Wood’s Countdown jQuery plugin, just a hunch. Either way, you get the idea.

Making Silverlight content region occupy all available browser space

I know, I know. It’s been a while and I’ve been busy. I will do what I can to make up for it. Here’s the first.

So as I’ve mentioned, I’m starting from ground zero on Silverlight and I’m documenting stuff I ran into that I found frustrating so that it may help some other poor soul and so I have a place to check when it happens again (and it probably will). This little bugger was particularly frustrating because I wasn’t focused at the time. Writing good multi-threaded code does not mean that you can write good code when you’re multi-threading.

So what was I trying to do? I had already written my XAML and my code behind written and they were working fine. All I needed to do now was to make my Silverlight control take up all the space available in the browser window. Simple, right?

Well, it should have been. I tried setting the LayoutRoot’s height and width to Auto. No good. Set height and width to 100% on the <object> tag. Nope. Time to reference the library. Pro Silverlight 3 in C#, surely that must know. It says:

“… you might prefer to remove the Width and Height attributes from the <UserControl> start tag. That way, the page will be sized to match the Silverlight content region, which in turn is sized to fit the browser window, and your Silverlight content will always fit itself into the currently available space.”

Tricky wording there. It will fit itself into the currently available space, but it isn’t sized to take all the available space, which is what I wanted. So what was the key? When you have Visual Studio create a new Silverlight test page, you’ll notice that it adds a style, a style that I didn’t have. It looks like this:

<style type="text/css">
html, body {
    height: 100%;
    overflow: auto;
}

body {
    padding: 0;
    margin: 0;
}

#silverlightControlHost {
    height: 100%;
    text-align:center;
}
</style>

As soon as I added that to my page, I got just what I was looking for. I should mention here that this makes the assumption that your silverlight <object> tag is nested in a div whose id is silverlightControlHost. Give it a shot and I hope this helps!

<style type=”text/css”>
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
text-align:center;
}
</st<style type=”text/css”>
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
text-align:center;
}
</style>yle>

Easy Access to the crmForm.ObjectId from CRM 4.0 entities

Note: The content in this post, like most of my posts, is likely unsupported.

Warning: This is a lot of content for a very few lines of code. I ramble so that you can learn the how and the why. More advanced developers and/or less patient readers may want to go straight for the code.

If you’re anything like me, you spend a lot of time in CRM. I love it, as does most anyone I’ve met who’s tried it. Having said that, there are a few things about it that are intentionally hidden from the user’s view and with good reason.

A great example of that is the address bar. For most of us who deal with CRM, we know that CRM keeps track of entities by using GUIDs. Furthermore, we know that the easiest built-in way to get the current entity’s GUID is to get it from the URL. One quick way to do that is to hit F11 which will cause the current browser window to go full screen and the address bar is available by moving your mouse to the top of the window. It’s a little annoying because it usually takes me 3 steps:

  1. You have to hit F11 and move the mouse to the top of the window to show the address bar.
  2. You have to click in the address box, which usually makes the address bar hide itself, so you have to click in it again.
  3. You have to highlight only the GUID before copying it, or copy and paste the whole URL and remove everything but the GUID.

Now if you haven’t been exposed to that method, you’re welcome, but hang on because this post should save you the trouble. 3 repetitive steps that annoy me and are preventable are usually enough for me to search for a programmatic solution. I’m a developer and I live by DRY. (Don’t repeat yourself)

So there are many ways to accomplish this I’m sure, but here’s my way. I should mention here that I tend to deal with the database side of things a great deal as well, so I knew from the beginning that I wanted to copy the GUID to my clipboard.

Initially my thought was to add a button to the toolbar, or maybe even add a copy command to the actions menu, but while I was making this little snippet I realized that often times I’m running database queries against these GUIDs and it would be nice to see the GUID on the screen at all times. I decided to tap into the status bar. For all the entities I checked it’s always down there, and it seems to always have room enough for some other text, say… a GUID. 🙂

My approach: This is actually pretty straight-forward. Each entity’s form has a crmForm.ObjectId (yes, case sensitive) that is the GUID for the current record. So, I figured I would add some JavaScript to embed the ObjectId in a UI element on the form. Nowadays, anytime I hear JavaScript I think jQuery. So, how to get jQuery on a CRM form? This has been documented in several places on the interwebs. Before I post it here online, I need to ask the person I got it from if I can share this particular approach.

Now that you’re referencing jQuery, you have a little horsepower behind you. So, let’s add the line that will show the GUID in the status bar:

$("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span>");

Huh? What’s all that? Let’s break it down:

  • First, it finds the element whose id is crmRenderStatus.
  • Next, it finds the closest td tag (in this case, its parent td)
  • Then, it appends the HTML that I’m specifying while injecting the crmForm.ObjectId

Here’s the result:

image

What you wind up with is quite simply the GUID nested in a span tag, positioned right next to the Status on the status bar. It’s important to note that the fact that I’ve tucked the content in a span tag with a specific ID property is both intentional and required. Great! Now I can see the GUID, but I can’t copy it. How can I fix that? Easy enough. Just use good old jQuery again and wire up a double click event handler to the GetObjectId span that contains the GUID, like this:

$("#GetObjectId").dblclick(function() {
    window.clipboardData.setData('Text', this.innerHTML);
});

Does that look like Greek? OK, let’s break that down:

  • First, we’ll find our newly added span element with the id of GetObjectId.
  • Next, we’ll attach a handler to the double click event (jQuery .dblclick method).
  • Finally, we’re defining an anonymous function that details what we want to do when the double click event fires.

Now this works, but you don’t get any visual indication that you’ve copied the GUID. To handle this, I’m changing the “UI modification” line to include a span that just has the text ” Copied…”. This line starts out invisible since you haven’t copied the GUID until you double click on it.

$("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span><span id='ObjectIdCopied' style='display:none;'>&nbsp;Copied...</span>");

I’m also going to change the handler’s anonymous function to show the ” Copied…” text by fading it in and to allow them to get a second copy indication by fading it out.

$("#GetObjectId").dblclick(function() {
    window.clipboardData.setData('Text', this.innerHTML);
    $("#ObjectIdCopied").fadeIn("fast").fadeOut("slow");
});

This results in a brief moment that looks like this (insert imagined fade-in and fade-out here)
image

There we have it. A few lines of code that save me some hassle many times throughout the day. You can see the detail in this post by Jim Wang, but the other thing that I do is wrap this in an if statement that checks to make sure that all this only happens if you’re a System Administrator or System Customizer. Alright, I warned you this was a long post for such a small amount of code. Here’s the code all wrapped up. Hope this helps!

if (UserHasRole("System Administrator") || UserHasRole("System Customizer"))
{
     $("#crmRenderStatus").closest("td").append("<span id='GetObjectId'>" + crmForm.ObjectId + "</span><span id='ObjectIdCopied' style='display:none;'>&nbsp;Copied...</span>");
     $("#GetObjectId").dblclick(function(){
         window.clipboardData.setData('Text', this.innerHTML);
         $("#ObjectIdCopied").fadeIn("fast").fadeOut("slow");
    });
}

There is one other addition to all of this which you may have noticed. We use a UserHasRole method to make sure that I’m not showing everyone the GUID. That’s not because I want to keep it a secret, it’s because I don’t need users telling me that CRM is emiting corrupted text.

Cheers!

Microsoft releases new CRM case study : Access MediQuip

Well, I have to say that I’m flattered. It’s always great to look back on what you’ve created and get a sense of self-fulfillment. For me, today is no exception. I work for Access MediQuip as their lead developer and software architect. We deal with challenges every day – don’t we all? – and I have to say that I really enjoy them, or more specifically overcoming them. It feels good to be proud of what you’ve made, it feels great when your boss tells you that you’ve done a great job, but it feels pretty stellar when Microsoft likes it enough to write a case study about it.

I have to say that although the proverbial buck stops here when it comes to our solution, it’s great to have had the opportunity to work with great people too. While a lot of the development for our platform has been handled in-house, I was able to draw on the expertise of leaders in the industry as well. I knew that I wanted to involve someone who , like me, could “bring the heat” and in my mind that meant a Microsoft MVP.

In particular, I’m referring to none other than Mitch Milam. Mitch is Chief Technologist at CRM Accelerators and is a Microsoft CRM MVP. He brought the skills I was looking for in the CRM space. I’ve worked with Mitch since March of last year, and it’s been great. I’m not just ‘blowing sunshine up his skirt’ either. It continues to be a great experience, and I can highly recommend him to any clients looking to push the CRM/xRM envelope. I think we’ve both grown from working with each other, and I plan on continuing that growth. Cheers Mitch! – now where’s my $5? 😉

I love looking back on what I’ve created, but I have to say that it’s the tip of the iceberg in comparison with what we want to do with xRM. I’ll keep you posted for what interesting tid-bits I can share.

Here’s a link to the case study:

http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?casestudyid=4000006368

Mitch’s blog can be found here:

http://blogs.infinite-x.net/

How to deal with stubborn Silverlight (a.k.a. stubborn me)

Alrighty then… So here we are in this new decade of ours so I should start with a warm welcome! With a new decade comes new technology and this is shaping up to be no exception. To start things off right, I decided to bite into Silverlight. Let’s face it, Microsoft has had the old Windows Forms model for quite some time and they’ve made it pretty clear that they think WPF is pretty spiffy, and I tend to agree. Now, since the last major paradigm shift that I experienced was with ASP.NET back in the very early part of the last decade, I’ll let Silverlight kick off this decade. So, what’s the scoop today?

I decided to start with some small composite applications in Silverlight. The first of these was supposed to be simple. This is going to be tucked into my company’s internal CRM 4.0 and will simply aggregate notes from different sources and display them in the Silverlight user control. Now, I should mention that I already had this thing working using good old HTML, but I had to start somewhere!

The plan here was just to have a list box that would show the notes. Nothing crazy, should be quick right? Yes, and no. I hit speed bumps and you may too so I hope this helps. I started with the default bit of XAML:

<UserControl x:Class="MyNamespace.MainPage" 
   xmlns="... mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">    
  <Grid x:Name="LayoutRoot">
  </Grid>   
</UserControl>

Great! Let’s get started. So first I’ll need a ListBox, that’s easy enough. I’ll save you all the extra stuff you probably don’t need help with like styling gradients and such. So that gets us to here:

<Grid x:Name="LayoutRoot">   
   <ListBox />
</Grid>

Crazy exciting so far. If I plan on showing anything in this ListBox I’m going to need to add items. Now I’m serving up data from data from a database and I want to customize how the ListBoxItems are going to look, so I’ll need to create a template for that. Again, I’ll spare you all the visual fluff:

<DataTemplate x:Key="NoteTemplate">    
    <Border CornerRadius="10">    
     <Grid>    
      <Grid.RowDefinitions>    
       <RowDefinition />    
       <RowDefinition />    
       <RowDefinition />    
      </Grid.RowDefinitions>    
      <TextBlock Text="{Binding Category}" Grid.Row="0" />    
      <StackPanel Orientation="Horizontal" Grid.Row="1">    
       <TextBlock Text="Created on " />    
       <TextBlock Text="{Binding CreatedOnDate}" />    
       <TextBlock Text=" at " />    
       <TextBlock Text="{Binding CreatedOnTime}" />    
       <TextBlock Text=" by " />    
       <TextBlock Text="{Binding CreatedBy}" />    
      </StackPanel>    
      <TextBlock Text="{Binding Description}" Grid.Row="2" />    
     </Grid>    
    </Border>    
  </DataTemplate>   

OK, so now we’ve got the DataTemplate defined, let’s reference it on our ListBox:

<ListBox ItemTemplate="{StaticResource NoteTemplate}" />   

OK, that should do it. Let’s take a look:

image

Hmmm… not quite what I was expecting. I didn’t specify a width, so I would expect it to stretch. Alas, no such luck. As it turns out, the default style for a ListBoxItem sets the HorizontalContentAlignment to Left but we want it to stretch. So, we’ll have to define a style on the ListBox’s ListBoxItem in order to set it to stretch. How do we accomplish that? First, let’s define the style:

<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">   
  <Setter Property="HorizontalContentAlignment" Value="Stretch" />   
</Style>   

Now that we have the style defined. Since we’re instantiating the ListBoxItems programmatically through Data Binding, we can’t set the style directly on the ListBoxItem’s XAML because it’s not there. However, we can get to it through the ListBox’s ItemContainerStyle property.

<ListBox ItemTemplate="{StaticResource NoteTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" />   

OK, let’s take another look:

image

What the heck? Now it’s all stretched, but way too far! How can we solve that? My initial guess is that we just need some wrapping. It’s the description TextBlock that has too much text and is pushing us way out in right field. So within short order I add TextWrapping to the TextBlock like this:

<TextBlock Text="{Binding Description}" Grid.Row="2" TextWrapping="Wrap" />

Wow, for some reason that did absolutely nothing! Frustrating to say the least. After trying several other things I’m having trouble finding the solution, so I go and talk to my friend Bing. He points me to lots of message boards where people have the same issue, but they always seem to end 1 of 2 ways. Either they want you to specify the width or they never actually come to a solution. Now, if you are in a situation where you can specify the width, then you’re set. It will happily wrap the text for you. In fact, during my testing it appears that you can also set the MaxWidth and that will also work if you have that luxury. Unfortunately, I didn’t. I don’t know how big or how small this thing is going to be, and I don’t want to constrain the users.

So here’s the secret that worked for me. After reaching that point of too much frustration and not enough sleep, I changed 1 property on the ListBox and it did the trick. The ListBox has an attached property of a ScrollViewer. It puts horizontal and vertical scrollbars on the edges of your control for you. The ScrollViewer has a property called HorizontalScrollBarVisibility. In a fit of trial and error, I set that to Disabled and voila!

<ListBox ItemTemplate="{StaticResource NoteTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />

Suddenly I’m right where I want to be:

image

It seems that setting the ScrollViewer’s HorizontalScrollBarVisibility to Disabled works its magic in the rendering enough to realize that without a horizontal scroll bar and with text wrapping that the actual rendered width is the same as the parent ListBoxItem’s width. Here’s the code in total that I used:

<UserControl
    xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation" >http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>"
    xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml" >http://schemas.microsoft.com/winfx/2006/xaml</a>"
    xmlns:d="<a href="http://schemas.microsoft.com/expression/blend/2008" >http://schemas.microsoft.com/expression/blend/2008</a>"
    xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006" >http://schemas.openxmlformats.org/markup-compatibility/2006</a>"
    x:Class="MyNamespace.CommentsRollup" mc:Ignorable="d" Loaded="UserControl_Loaded">
 <UserControl.Resources>
  <DataTemplate x:Key="NoteTemplate">
    <Border CornerRadius="10">
     <Grid>
      <Grid.RowDefinitions>
       <RowDefinition />
       <RowDefinition />
       <RowDefinition />
      </Grid.RowDefinitions>
      <TextBlock Text="{Binding Category}" />
      <StackPanel Orientation="Horizontal" Grid.Row="1">
       <TextBlock Text="Created on " />
       <TextBlock Text="{Binding CreatedOnDate}" />
       <TextBlock Text=" at " />
       <TextBlock Text="{Binding CreatedOnTime}" />
       <TextBlock Text=" by " />
       <TextBlock Text="{Binding CreatedBy}" />
      </StackPanel>
      <TextBlock Text="{Binding Description}" Grid.Row="2" TextWrapping="Wrap" />
     </Grid>
    </Border>
  </DataTemplate>
  <Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
   <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  </Style>
 </UserControl.Resources>
    <Grid x:Name="LayoutRoot">
     <ListBox ItemTemplate="{StaticResource NoteTemplate}" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
    </Grid>
</UserControl>

I sure hope this saves you some frustration. If any of you Silverlight gurus out there know of a better way to accomplish this, please let me know the right way to do it. Thanks and enjoy!

CRM 4.0 Update Rollup 8 released

Microsoft released CRM 4.0 Update Rollup 8 yesterday. This rollup is packed with fixes, most notably:

  • E-mail Router support for Exchange 2010 and for Exchange Web services is added.
  • Users cannot assign activities after the activities are deleted from a queue.
  • Although Microsoft Office 2010 is still in beta and is not officially supported, Microsoft Dynamics CRM 4.0 was tested together with Microsoft Office 2010.

2010 here we come! A great job by the CRM Dev Team for the continuous stream of updates. I really think it helps to keep CRM a vibrant and robust platform. Kudos! You can always check the Microsoft Dynamics CRM Team Blog here.

Deleting a user the right way in CRM 4.0

I always enjoy getting stumped, and sometimes things come out of left field and you find yourself scratching your head for a while. This happened to me recently at work when I had a Help Desk ticket escalate out of the Help Desk and up to me. Now, normally I try to let the Help Desk staff run with problems because I think it’s important for their own professional growth but this had me digging and missing the obvious. The help desk ticket was as wordy as long-winded as you’d expect.

“User can’t add items to order”.

Such incredible insight in 6 short words. OK, I’ll be honest, an order number would have helped but I wasn’t going to hold my breath. So, I try to add an item to an order and it works just fine. Later, I get a screenshot and an order number so I figure we’re in business. But what’s this?

Error
“The selected user or the user trying to log on has not been assigned a security role, and does not have sufficient privileges for this action. For more information, contact your Microsoft Dynamics CRM administrator.”

OK, that’s odd. This is clearly a built-in CRM error message. I quickly check the user’s roles and everything’s just fine, so I try to add an item to the order myself. My assumption is that since I’m a System Administrator I shouldn’t have a problem, but I do. Same error message! How can this be!? Well, if it’s happening to me as a System Administrator, then it must not be my roles in question and it isn’t the users. “The selected user”…. of course! This isn’t my order, so let me check the security roles belong to the order’s owning user. Take a look at the image and tell me what’s missing.

NoRoles

Guessed it yet? No Roles! In our case, the owner of the order was user that was no longer with the company. Someone on the Help Desk staff took it upon themselves to simply remove all the user’s roles in CRM an assumed that was sufficient.  In fact, the user’s account was still active.

So what is the appropriate route for dealing with user’s in such a case? My suggestion would involve 2 steps:

1. If the user isn’t with the company anymore, someone will likely take over their work load. The CRM Dev Team has thought about this and has added a handy little feature for doing just that.

ReassignRecords

Simply open the user form for the user in question, hit the Actions menu, and choose Reassign Records. Doing so allows you to reassign them to yourself or another user, as shown below.

ChooseReassignRecipient

Do take the time to read the text in the yellow box. It doesn’t matter what state the record is in, if you reassign it to yourself, it’s yours. That includes all deactivated records too.

2. Now that all the records belong to someone else, you should disable the user’s account so that it’s tucked away for safekeeping.

Cheers!