Saturday, January 31, 2009

Programmatically saving a Microsoft CRM Form

To force Microsoft CRM to save the contents of a custom CRM form you can use the following javascript:
crmForm.Save();
Note this only saves data within CRM not data within your IFrame.

Maximizing a customized form in Microsoft CRM

Sometimes it's desirable to maximize your CRM customized form so more screen is visible for your custom form/IFrame.

You can do this by placing the following script in the OnLoad event of the CRM customized form:
OnLoad()
{
window.moveTo(0,0);
window.resizeTo(screen.availWidth, screen.availHeight);
}

Process.GetProcesses() on the Compact Framework

Process.GetProcesses() is not supported on the Compact Framework 3.5 and often this is a desirable thing to do. But luckily there are workarounds.

You can P/Invoke the required toolhelp.lib function Process32Next passing in a PROCESSENTRY32 struct and a Toolhelp32Snapshop.

The signature looks like this:
BOOL WINAPI Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
There is a fair bit of code required to get this working. You could implement this yourself or use an implementation from the Software Development Framework from OpenNETCF to save you a few hours of pain.

Coding this API looks like so:
var processes = OpenNETCF.ToolHelp.ProcessEntry.GetProcesses();

foreach (OpenNETCF.ToolHelp.ProcessEntry process in processes)
{
Console.WriteLine(process.ExeFile);
}
The call to Toolhelp.ProcessEntry.GetProcesses() returns an array of ProcessEntry objects. You can then kill the process, get the process id, get the associated modules, get the base address, thread count etc..

Saturday, January 24, 2009

Collection of Microsoft CRM posts

Even though this blog is primarily about mobility, I post stuff outside of mobility as well as often applications on mobile doesn't just end there. Typically LOB apps use a whole host of back office software, middleware and services.

I've been posting a few articles on Microsoft CRM 4.0 recently, and you can view them here. I intend to add to this collection as there are many challenges from a custom dev perspective on this technology that I have recently found solutions to.

Tuesday, January 20, 2009

Submitting an IFramed Web App running within Microsoft CRM 4.0 - from CRM - a better approach

I published a post recently regarding submitting a ASP.NET application running within an IFRAME in CRM here.

This solution is ok but not brilliant.

I have found a better solution which is to call the click() method on a button in the ASP.NET form within the CRM Customization OnLoad event.

The advantage of this is we can call a specifc event handler - server side from CRM saving us the need to sumit the form on every postback - which could cause problems depending on how you have implemented your ASPX.

So how does CRM get a handle to the button? Well we render some JavaScript in a common class that each Web Form (that is interested in this behavior) inherits from. Calling this JavaScript returns a handle to the button for the specific form in question. Doing this saves us the need to duplicate code in every page.

So our base page class looks like this:
public abstract class CrmSupport : Page
{

protected CrmSupport()
{
Page.Load += OnPageLoad;
}

private void OnPageLoad(object sender, EventArgs e)
{

SaveButton.Attributes["style"] = "visibility:hidden";

if (SaveButton != null)
{
ClientScript.RegisterStartupScript(typeof (string), "saveButton",
@"<script language=javascript>function GetSaveButton(){return
document.getElementById('" + SaveButton.ClientID + "');}</script>");
SaveButton.Click += SaveButton_Click;
}
}

private void SaveButton_Click(object sender, EventArgs e)
{
OnSave();
}

protected virtual void OnSave()
{
//Do any common save process.
}

protected abstract Button SaveButton
{
get;
}
}
So the class is fairly light weight and there is no HTML, it's just a C# class. We have made it abstract and implemented a abstract property named SaveButton. You could make it default so instances where the save function is not required, but in this implementation it is mandatory for derived classes. In the derived class (the Web Form class) we implement the property like so:
public override Button SaveButton
{
get { return Save; }
}
Where Save is a reference to our button.

We also register a OnLoad event handler in the base form so that we can render some javascript at runtime. This javascript creates a function named GetSaveButton(). It will return an object to CRM so CRM customizations can call it. CRM needs to do this so that it can call the click() method on the button resulting in a server side Click event. We also set the style of the button to hidden. Note we must use styles as opposed to hidding the button so that we can get access to the ClientID property at runtime. Setting the server side visibility essentially removes it from the generated HTML.

Our web form HTML looks like the following:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SampleInvokeButton._Default" %>


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Save" runat="server" Text="Button"/>
</div>
</form>
</body>
</html>
The code behind looks like so:
public partial class _Default : CrmSupport
{

protected override Button SaveButton
{
get { return Save; }
}

protected override void OnSave()
{
base.OnSave();
//Called from CRM to Save data. Most likely call our service layer passing a DTO.
}
}
So here we have our overrides property that returns an instance of our button to service our base forms request when it asks for it.

We have hooked up the OnSave event handler (server side) event in the base form that gets called when the button is clicked. Each implementation can override this event as desired. This gives the opportunity to process some common application logic for each page without haveing to duplicate this logic in each page.

Now all that remains is the javascript CRM side and all that is required is to place the following script in the OnSave event in the CRM customizations for the entity you are interested in where iframeName is the name of your iframe:
var button = document.getElementById(iframeName).contentWindow.GetSaveButton();
if (button != undefined)
button.click();
else
alert("Save is not permitted");
So CRM is driving the save here. We could, if we wanted to, let the form handle the click event by making the javascript more coarse grained ASPX end and finer CRM end - this is a debatable subject though. I opted for CRM doing most of the processing.

Monday, January 19, 2009

The smart way to removing multiple memory applet references in Windows Mobile

I wrote an article recently to get over the problem of multiple references to an application in Windows Mobile memory applet when loading multiple forms here.

Thanks to monxalo's suggestion to using extension methods support in the .NET 3.5 we can design a more elegant solution.

I just created a simple class named FormExtensions in my UI namespace with the following code:
public static class FormExtension
{
public static DialogResult ShowDialog(this Form owner, Form form)
{
form.Owner = owner;
return form.ShowDialog();
}
}
Nothing too complex here. So in our client code where we would normally load another form we could now code something like the following:
private void OnButtonClick(object sender, EventArgs e)
{
this.ShowDialog(new Form2());
}
This assumes the FormExtensions class is in the same namespace as the UI layer. If not you'd have to fully qualify the extension class. I recomend putting it in the same namespace as the UI though.

Sunday, January 18, 2009

No Visual Studio 2008 templates after installing Enterprise Library 4.1

I installed the Enterprise Library 4.1 successfully today and after doing so I attempted to create a project in Visual Studio 2008 and then encountered this warning message:



Then when I loaded the new project dialog in VS, all project templates were missing.

A simple solution to this problem is closing down all instances of Visual Studio then run this on the command-line: devenv /installvstemplates

Thursday, January 08, 2009

A couple Windows Mobile Developer resources

The Windows Mobile Developer Center has recently had a lick of paint, worth a look and worth bookmarking as there is a lot of information here: http://msdn.microsoft.com/en-gb/windowsmobile/default.aspx

Another site worth looking at is the Windows Mobile Developer Network: http://www.microsoft.com/windowsmobile/en-us/developers/default.mspx. This site also contains many RSS feeds and useful info.

Lastly but not least, here is a link to a page on the Windows Mobile Developer Center that lists many Windows Mobile blogs and wikis: http://msdn.microsoft.com/en-gb/windowsmobile/bb264323.aspx

MVP Summit 2009

Well it's that time of year again! The summit is closing in on us and I hope I can make it as my current project deliverables are very tight at present.....

CA1502 Microsoft.Maintainability - .NET Compact Framework 3.5 Func to the rescue...

If you are using the Microsoft .NET Compact Framework 3.5 no doubt you have encountered the new Func delegate as luckily for us device devs, Func is supported on the CF. Pretty much the whole of LINQ uses Func’s and lambdas to get the job done.

In addition, if you are using Code Analysis in Visual Studio (FxCop) then you might have encountered the following error: CA1502: Microsoft.Maintainability : Function has a cyclomatic complexity of n. Rewrite or refactor.

You might get this if you have written some code like in this article: http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/16fdc314-4719-47da-9cb3-2877f29a47b9/

Typical if/else/if/else/if/else drives developers mad. In that link about, the developer has 26 if’s!!

I’m one of those developers that dislikes this type of code. It’s really hard to read and maintain, which is why FxCop is complaining about it.
But as with everything, there is a simple solution and now Func makes this easier for us. I decided to knock up a quick solution to this.

So as per the post above, we have our context class, and the idea behind this code is to set the constructor with a different strategy type based on the passed string (just as the dev requires in the post). So we have our dummy Context class and it looks like the following:
public class Context
{
private readonly Strategy _strategy;
public Context(Strategy strategy)
{
_strategy = strategy;
}

public Strategy Strategy
{
get
{
return _strategy;
}
}
}
Now for the Strategy types, the dev in the article has 26 of these, but for simplicity, I’ve just created 3, but you get the idea, the code is very easily extended:
public abstract class Strategy
{
}
public class Strategy1 : Strategy
{
}
public class Strategy2 : Strategy
{
}
public class Strategy3 : Strategy
{
}

Now for getting the context, I’ve created a static factory class that returns a context based on a string passed to it:
public static class ContextFactory
{
private static readonly Dictionary<string, Func<Context>>
dictionary = new Dictionary<string, Func<Context>>
{
{"1", () => new Context(new Strategy1())},
{"2", () => new Context(new Strategy2())},
{"3", () => new Context(new Strategy3())}
};

public static Context CreateContext(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");

return dictionary[name]();
}

public Strategy Strategy
{
get
{
return _strategy;
}
}

}
So that's the complete example. Calling the code is done as follows:
Context context = ContextFactory.CreateContext("3");
If you run that code and inspect the Strategy property, it will equal Strategy3.

So lets explain the code abit. Instead of having lots of conditional if/else/if/else statements to figure out what name is equal to, we have created a generic dictionary class, where the key is the identifier that identifies the type we want passed to the Context constructor. The value is to set the the new Func delegate that allows us to execute the code the we want for the passed key. We use the Func so that we return the specified type.

So the line:
return dictionary[name]();
is essentially executing the delegate for the dictionary item "name". We would need to check if the item exists in a real world example and throw a meaningful exception in this case. This was left out to clarify the code.

In addition, FxCop is happy no matter how many items we add to our dictionary.