![]() |
#1 |
Участник
|
(a small change added that simplifies the SmallVEControl class definition)
With the release of NAV 2009 SP1 CTP2 (to MVPs, TAP and BAP) and the official release of the statement of Direction, I can now write about the last part of the integration to Virtual Earth. People who hasn’t access to NAV 2009 SP1, will unfortunately have to wait until the official release until they can take advantage of this post. Please not that you should read Part 1, Part 2 and Part 3 of the Integration to Virtual Earth – and you would have to have the changes to the app. described in these posts in order to make this work. This post will take advantage of a functionality, which comes in NAV 2009 SP1 called Extensibility. Christian explains some basics about extensibility in a post, which you can find here. The Goal ![]() As you can see on the above picture, we have a control, which is able to show the map in NAV of the customer location, and as you select different customers in the list, the map changes. The changes in the map happens without any user interference, so that the user can walk up and down in the list without being irritated. In the Actions menu in the part, we will put an action called Open In Browser, which will open up a map in a browser as explained in part 3. Note that the Weather factbox is not shown here. What is it? The Control inside the Customer Map Factbox is basically just a browser control, in which we set a html document (pretty much like the one described in part 3) and leave it to the browser control to connect to Virtual Earth and retrieve the map. I do not connect to web services from the browser control, instead we transfer parameters of the current customer location to the control. Although the internal implementation is a browser control, we don’t do html in NAV and we don’t give the control any URL’s or other fancy stuff. The way we make this work is to have the control databind to a Text variable (CustomerLocation), which gets set in OnAfterGetRecord: CustomerLocation := 'latitude='+FORMAT(Latitude,0,9)+'&longitude='+FORMAT(Longitude,0,9)+'&zoom=15'; The factbox isn’t able to return any value and there isn’t any reason right now to trigger any events from the control. So now we just need to create a control, which shows the string “latitude=50&longitude=2&zoom=15” differently than a dumb text. How is the control build? Let’s just go through the creation of the VEControl step by step. 1. Start Visual Studio 2008 SP1, create a new project of type Class Library and call it VEControl. 2. Add a reference System.Windows.Forms , System.Drawing and to the file C:Program FilesMicrosoft Dynamics NAV60RoleTailored ClientMicrosoft.Dynamics.Framework.UI.Extensibility.dll – you need to browse and find it. Note that when you copy the VEControl.dll to it’s final location you don’t need to copy this DLL, since it will be loaded into memory from the Client before your DLL is called. 3. Open Project Properties, go to the Signing tab, and sign your DLL with a new key. ![]() 4. In the Build Events Tab add the following command to the Post-Build Event window: copy VEControl.dll "C:Program FilesMicrosoft Dynamics NAV60RoleTailored ClientAdd-ins" this ensures that the Control gets installed in the right directory. 5. Delete the automatically generated class1.cs and add another class file called VEControl.cs 6. Add the following class to the file: /// <summary> /// Native WinForms Control for Virtual Earth Integration /// </summary> public class VEControl : WebBrowser { private string template; private string text; private string html = "<html><body></body></html>"; /// <summary> /// Constructor for Virtual Earth Integration Control /// </summary> /// <param name="template">HTML template for Map content</param> public VEControl(string template) { this.template = template; this.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(VEControl_DocumentCompleted); } /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void VEControl_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (this.DocumentText != this.html) { this.DocumentText = this.html; } } /// <summary> /// Property for Data Binding /// </summary> public override string Text { get { return text; } set { if (text != value) { text = value; if (string.IsNullOrEmpty(value)) { html = "<html><body></body></html>"; } else { html = this.template; html = html.Replace("%latitude%", GetParameter("latitude", "0")); html = html.Replace("%longitude%", GetParameter("longitude", "0")); html = html.Replace("%zoom%", GetParameter("zoom", "1")); } this.DocumentText = html; } } } /// <summary> /// Get Parameter from databinding /// </summary> /// <param name="parm">Parameter name</param> /// <param name="defaultvalue">Default Value if the parameter isn’t specified</param> /// <returns>The value of the parameter (or default)</returns> private string GetParameter(string parm, string defaultvalue) { foreach (string parameter in text.Split('&')) { if (parameter.StartsWith(parm + "=")) { return parameter.Substring(parm.Length + 1); } } return defaultvalue; } } Note, that you will need a using statement to System.Windows.Forms. This class gets initialized with a html template (our javascript code) and is able to get values like “latitude=50&longitude=2&zoom=15” set as the Text property and based on this render the right map through the template. The reason for the DocumentCompleted event handler is, that if we try to set the DocumentText property in the browser before it is done rendering the prior DocumentText, it will just ignore the new value. We handle this by hooking up to the event and if the DocumentText is different from the value we have – then this must have happened and we just set it again. We are actually pretty happy that the control works this way, because the javascript is run in a different thread than our main thread and fetching the map control from Virtual Earth etc. will not cause any delays for us. Now this is just a standard WinForms Control – how do we tell the Client that this is a control, that it can use inside the NAV Client? The way we chose to implement this is by creating a wrapper, which is the one we register with the NAV Client and this wrapper is responsible for creating the “real” control. This allows us to use 3rd party controls even if they are sealed and/or we don’t have the source for them. 7. Add a html page called SmallVEMap.htm and add the following content <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|