<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">hughpyle</title><subtitle type="html">Hugh Pyle's technology weblog</subtitle><id>http://blogs.msdn.com/hughpyle/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/hughpyle/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2006-06-22T13:55:00Z</updated><entry><title>Usability Studies</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2008/11/14/usability-studies.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2008/11/14/usability-studies.aspx</id><published>2008-11-14T18:16:00Z</published><updated>2008-11-14T18:16:00Z</updated><content type="html">&lt;P&gt;Do you use SharePoint and work with &lt;A href="http://technet.microsoft.com/en-us/magazine/cc160900.aspx" target=_blank mce_href="http://technet.microsoft.com/en-us/magazine/cc160900.aspx"&gt;Groove&lt;/A&gt;? Microsoft's User Research Group is conducting series of studies for &lt;A href="http://www.microsoft.com/sharepoint/default.mspx" target=_blank mce_href="http://www.microsoft.com/sharepoint/default.mspx"&gt;SharePoint products and technologies&lt;/A&gt; at the Microsoft campus in Redmond, WA, and is looking for participants in the Puget Sound area&lt;/P&gt;
&lt;P&gt;The research team is looking for individuals who use SharePoint at least twice a week and have experience working with Groove. Each participant will receive a gift item they select from a list of some of Microsoft's most popular hardware and software titles.&lt;/P&gt;
&lt;P&gt;If you are interested please email &lt;A href="mailto:itusable@microsoft.com" mce_href="mailto:itusable@microsoft.com"&gt;itusable@microsoft.com&lt;/A&gt; with your name and phone number, with "Groove" in the subject line.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9075380" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Groove, Step By Step</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2008/01/24/groove-step-by-step.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2008/01/24/groove-step-by-step.aspx</id><published>2008-01-24T20:24:00Z</published><updated>2008-01-24T20:24:00Z</updated><content type="html">&lt;P&gt;New from Microsoft Press: &lt;A class="" href="http://www.amazon.com/Microsoft-Office-Groove-2007-Step/dp/0735625239/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1201194252&amp;amp;sr=1-1" mce_href="http://www.amazon.com/Microsoft-Office-Groove-2007-Step/dp/0735625239/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1201194252&amp;amp;sr=1-1"&gt;Microsoft® Office Groove® 2007 Step by Step&lt;/A&gt;, by Rick Jewell and John Pierce.&lt;/P&gt;
&lt;P&gt;Sounds like a good one.&amp;nbsp; Rick has been doing this Groove stuff for a while, and knows his subject well.&lt;BR&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7226638" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Silverlight in Groove</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2007/06/21/silverlight-in-groove.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2007/06/21/silverlight-in-groove.aspx</id><published>2007-06-21T18:53:00Z</published><updated>2007-06-21T18:53:00Z</updated><content type="html">&lt;P&gt;(20070917 - updated to Silverlight 1.0)&lt;/P&gt;
&lt;P&gt;Sorry for the extended absence.&amp;nbsp; I've been heads down planning for Office "14" Groove, and quite removed from all the Groove 2007 activity.&amp;nbsp; But here's something new and relevant, that I'm quite excited about.&lt;/P&gt;
&lt;P&gt;&lt;A class="" title=silverlight.net href="http://silverlight.net/" mce_href="http://silverlight.net/"&gt;Silverlight&lt;/A&gt; - if you didn't already know - is a new plugin, with quite amazing capabilities.&amp;nbsp; Vector graphics, animation, storyboards, a very rich and clean object model... and it's all .NET and &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/ms747122.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms747122.aspx"&gt;XAML&lt;/A&gt;, and all running inside a browser.&amp;nbsp; As a platform for lightweight applications, I think it's really powerful.&lt;/P&gt;
&lt;P&gt;Groove Forms has a relatively restricted set of user interface capabilities.&amp;nbsp; It's designed&amp;nbsp;for building reasonably straightforward UI for data capture in small teams.&amp;nbsp; Forms with fields, views with columns, and a Groove workspace for distributed data storage.&amp;nbsp; But many applications would like to go beyond a simple forms-driven UI, and Groove Forms doesn't make that very easy.&lt;/P&gt;
&lt;P&gt;Silverlight in Groove Forms, though, would be quite a nice combination.&amp;nbsp; So here it is.&lt;/P&gt;
&lt;P&gt;This example is very simple: load the Silverlight control, interact with it in the Groove form, save some state into the Groove record, and load the state back into the control when reading or opening a record.&amp;nbsp; In this case the model itself is also very simple: a set of Path elements, drawn by the user.&amp;nbsp; It's a sketchpad.&amp;nbsp; But once you have these simple pieces, a whole set of other exciting things become possible.&amp;nbsp; Charts of data.&amp;nbsp; Interactive collaboration around a shared model...&lt;/P&gt;
&lt;H3&gt;A simple form&lt;/H3&gt;
&lt;P&gt;First let's create a very simple new form, and add four fields:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;A text field named "Title".&amp;nbsp; This is just so we can display something in the view.&lt;/LI&gt;
&lt;LI&gt;A static text field named "staticXaml": hidden.&amp;nbsp; We'll use this to bootstrap the Silverlight control.&lt;/LI&gt;
&lt;LI&gt;A static text field named "staticControl".&amp;nbsp; This will contain the actual Silverlight control in the form.&lt;/LI&gt;
&lt;LI&gt;A text field named "Data": hidden.&amp;nbsp; We'll use this to store some data that the user created.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Here's my version of this form.&amp;nbsp; The "staticControl" field has some placeholder text, just so I can find it easily.&lt;/P&gt;
&lt;P&gt;&lt;IMG title="A simple form" height=476 src="http://www.cabezal.com/msdnblog/18-silform.png" width=741&gt;&lt;/P&gt;
&lt;H3&gt;Some scripts&lt;/H3&gt;
&lt;P mce_keep="true"&gt;We'll use the JavaScript programming capabilities of Silverlight 1.0.&amp;nbsp; The &lt;A class="" title="Silverlight 1.0 SDK" href="http://www.microsoft.com/downloads/details.aspx?FamilyId=FB7900DB-4380-4B0F-BB95-0BAEC714EE17&amp;amp;displaylang=en"&gt;SDK&lt;/A&gt; contains a standard script file "Silverlight.js" to wrap all the important things about initializing the Silverlight control, and we'll use this simply by importing it into the Groove Form.&amp;nbsp; Then we'll write another script of our own.&lt;/P&gt;
&lt;P mce_keep="true"&gt;So, in the "Form Scripts" tab of our new form, let's add two scripts:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Silverlight.js, imported from the SDK, and&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;SilverlightLoaders.js, a new script we'll write here.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;In the "System callouts script" for this form, I have some one-line functions that call into SilverlightLoaders.js to do their work:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;in the OnBeforeInitialize() function:&amp;nbsp; a call to form_OnBeforeInitialize();&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;in the OnAfterInitialize() function:&amp;nbsp; a call to form_OnAfterInitialize();&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;in the OnBeforeSubmitData() function:&amp;nbsp; a call to form_OnBeforeSubmitData();&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;&lt;IMG title="Form scripts" height=451 src="http://www.cabezal.com/msdnblog/19-silformscripts.png" width=735&gt;&lt;/P&gt;
&lt;H3&gt;Loading the Silverlight control&lt;/H3&gt;
&lt;P mce_keep="true"&gt;A Silverlight control can be embedded directly into an HTML page, or can be created at runtime using script.&amp;nbsp; We'll use the latter, since Groove Forms doesn't give you a way to define arbitrary HTML directly in the form page.&amp;nbsp; The Silverlight.js script has some functions to create the control, and embed it within the current page.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The control needs a XAML canvas definition, that will be loaded when it first starts.&amp;nbsp; (Without an initial canvas, the control really doesn't do much of anything at all).&amp;nbsp; There are two ways to supply the XAML:&amp;nbsp; from a URL, or from an element in the page.&amp;nbsp; Since Groove doesn't always need to be connected to a network, we would prefer not to rely on a web server to supply this initial content, but rather distribute it within the Forms tool istelf.&lt;/P&gt;
&lt;P mce_keep="true"&gt;To do this, we write a XAML fragment into the "staticXaml" field declared earlier.&amp;nbsp; In the case I'm showing here, that fragment contains pretty much the whole application we're building.&amp;nbsp; Alternatively it could be just a skeleton -- the canvas -- and the rest of the model created later on the fly.&lt;/P&gt;
&lt;P mce_keep="true"&gt;So here's our initialization script, complete with all the extra gubbins we'll see later.&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;DIV class=code&gt;&lt;PRE&gt;&lt;/PRE&gt;// REQUIRES:&lt;BR&gt;// (hidden) static text field, named "staticXaml", to hold the bootstrap xaml&lt;BR&gt;// (visible) static text field, named "staticControl", where the control will be sited&lt;BR&gt;// (hidden) text field, named "Data", to store the data in&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Globals:&lt;BR&gt;var g_AgLoaded = false;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The silverlight control has loaded&lt;BR&gt;var g_AgControl = null;&lt;BR&gt;var g_AgRoot = null;&lt;BR&gt;var g_AgCanvas = null;&lt;BR&gt;var g_AgInk = null;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// ===== Groove callbacks (form events) =====&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Form is being initialized for the first time&lt;BR&gt;function form_OnBeforeInitialize()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; inkInitialize();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; createSilverlightControl();&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Form is being initialized, and Groove data is ready&lt;BR&gt;function form_OnAfterInitialize()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; inkInitialize();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tryLoadPaths();&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;function form_OnBeforeSubmitData()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; savePaths();&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// ===== Silverlight control initialization =====&lt;BR&gt;&amp;nbsp;&lt;BR&gt;function createSilverlightControl()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(g_AgLoaded &amp;amp;&amp;amp; g_AgControl)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The silverlight control is already loaded and ready.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Create a "script" tag containing an empty canvas.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This canvas will be the first item loaded into the Silverlight control.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var c = '&amp;lt;Canvas x:Name="staticCanvas" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="640" Height="480"&amp;gt;' +&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; '&amp;lt;InkPresenter x:Name="inkEl" Background="transparent" Width="500" Height="500" MouseLeftButtonDown="inkMouseDown" MouseMove="inkMouseMove" MouseLeftButtonUp="inkMouseUp" /&amp;gt;' +&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; '&amp;lt;Canvas x:Name="pathsCanvas" /&amp;gt;' +&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; '&amp;lt;/Canvas&amp;gt;';&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var s = document.createElement("script");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; s.setAttribute("type", "text/xaml");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; s.setAttribute("id", "initialXaml");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; s.text = c;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; document.getElementById("staticXaml").appendChild(s);&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Create the Silverlight control,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // which will then call the "canvas_loaded" function when ready.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Silverlight.createObjectEx({&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; source: '#initialXaml',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; parentElement:document.getElementById("staticControl"), &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; id:'AgControl1', &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; properties:{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; width:'1024',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; height:'1024',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; background:'transparent',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; inplaceInstallPrompt:true,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; isWindowless:'true',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; framerate:'24',&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; version:'0.90.0'},&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; events:{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; onError:null,&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; onLoad:canvas_Loaded},&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; context:null&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;BR&gt;&amp;nbsp;&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Callback from Silverlight when the initial canvas has been loaded&lt;BR&gt;function canvas_Loaded(control, userContext, rootElement)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgControl = control;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgRoot = rootElement;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgCanvas = control.content.findName("pathsCanvas");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgInk = control.content.findName("inkEl");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgLoaded = true;&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// ===== Utils, misc =====&lt;BR&gt;&amp;nbsp;&lt;BR&gt;function IsEditMode()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return( !GetIsSearch() &amp;amp;&amp;amp; !GetIsPreviewPane() &amp;amp;&amp;amp; !GetIsReadOnly() ) ;&lt;BR&gt;}&lt;BR&gt;&lt;/DIV&gt;
&lt;H3&gt;Ink and Paths&lt;/H3&gt;
&lt;P mce_keep="true"&gt;Here I'll let you read the code first.&amp;nbsp; This is pretty lifted much verbatim from &lt;A class="" href="http://blogs.msdn.com/webnext/archive/2007/06/01/silverlight-convert-ink-to-xaml.aspx" mce_href="http://blogs.msdn.com/webnext/archive/2007/06/01/silverlight-convert-ink-to-xaml.aspx"&gt;Laurence Moroney's blog&lt;/A&gt;; with the additional step of keeping a string array of all the ink paths in memory.&amp;nbsp; We'll use that as the way to load and save ink to Groove, later.&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;BR&gt;// ===== Ink data and event handling =====&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// We keep a (script) array: each element of the array is the xaml text of one drawn line.&lt;BR&gt;// This array is stored in the Groove record, as well-formed XML:&amp;nbsp; all the lines, then wrapped in a "Canvas" element.&lt;BR&gt;// To load this back in to Groove we parse the data with XMLDOM and walk its child elements,&lt;BR&gt;// passing each one to Silverlight in turn.&lt;BR&gt;&amp;nbsp;&lt;BR&gt;var g_AllPaths = new Array();&lt;BR&gt;&amp;nbsp;&lt;BR&gt;var g_CurrentStroke = null;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;function inkInitialize()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AllPaths = new Array();&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Mouse down event handler from the InkPresenter&lt;BR&gt;function inkMouseDown(sender,args)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(!IsEditMode())&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Do nothing&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Capture the Mouse&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgInk.CaptureMouse();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Create a new stroke&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke = g_AgControl.content.createFromXaml('&amp;lt;Stroke/&amp;gt;');&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Assign a new drawing attributes element to the stroke&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This, as its name suggests, defines how the stroke will appear&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var da = g_AgControl.content.CreateFromXaml('&amp;lt;DrawingAttributes/&amp;gt;');&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.DrawingAttributes = da;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Now that the stroke has drawing attributes&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Let's define them...&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.DrawingAttributes.Width = 1;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.DrawingAttributes.Height = 1;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.DrawingAttributes.Color = "Black"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.DrawingAttributes.OutlineColor = "Black"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(g_AgInk));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgInk.Strokes.Add(g_CurrentStroke);&lt;BR&gt;} &lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Add the new points to the Stroke we're working with&lt;BR&gt;function inkMouseMove(sender,args)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(!IsEditMode())&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Do nothing&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (g_CurrentStroke != null)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.StylusPoints.AddStylusPoints(args.GetStylusPoints(g_AgInk));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;} &lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Release the mouse&lt;BR&gt;function inkMouseUp(sender,args)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(!IsEditMode())&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Do nothing&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pathString = ""&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pathElement = "&amp;lt;Path Stroke='Black' Data='"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var n = g_CurrentStroke.StylusPoints.Count;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(i=0;i&amp;lt;n;i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(i==0)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pathString +="M "&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pathString +="L "&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pathString+= + g_CurrentStroke.StylusPoints.GetItem(i).X + "," +&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke.StylusPoints.GetItem(i).Y + " " &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pathElement+=pathString+"' /&amp;gt;"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addPath(pathElement);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgInk.Strokes.Remove(g_CurrentStroke);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_CurrentStroke = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgInk.ReleaseMouseCapture();&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// =====&lt;BR&gt;&amp;nbsp;&lt;BR&gt;// Add a path (xaml string) to the current drawing&lt;BR&gt;// and to the in-memory array of path strings&lt;BR&gt;function addPath(path)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var elPath = g_AgControl.content.createFromXaml(path);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgCanvas.children.add(elPath);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AllPaths[g_AllPaths.length] = path;&lt;BR&gt;}&lt;BR&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;H3&gt;Load and Save&lt;/H3&gt;
&lt;P mce_keep="true"&gt;To save the user's drawing into Groove, we use the form's OnBeforeSubmitData callback:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Join the array of paths we know about&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Wrap them all inside a &amp;lt;Canvas&amp;gt; tag&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Write this to the "Data" field on the form.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;So when you hit Save, the current version of the model is stored away in the Groove record, and diseminated to any other members in the workspace.&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;BR&gt;// Save current array of paths into the Groove record&lt;BR&gt;// (writing into the UI document, not the underlying record directly)&lt;BR&gt;function savePaths()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xaml = "&amp;lt;Canvas&amp;gt;" + g_AllPaths.join("") + "&amp;lt;/Canvas&amp;gt;";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SetHTMLFieldValue("Data", xaml);&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P mce_keep="true"&gt;To load a drawing from the current record -- when previewing a record, or when opening an existing record for editing -- I took a slightly more convoluted route.&amp;nbsp; I read the value of the Data field from the current record, and parse it with a regular XMLDOM object.&amp;nbsp; This gives us some advance validation that the data is well-formed XML, and it also makes it really easy to separate out each of the Path elements, then load them up into the Silverlight control.&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;BR&gt;// Load paths from an existing Groove record&lt;BR&gt;function tryLoadPaths()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // The Silverlight control loads asynchronously, so wait until it's called back to the page.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(g_AgLoaded &amp;amp;&amp;amp; g_AgControl &amp;amp;&amp;amp; g_AgRoot &amp;amp;&amp;amp; g_AgCanvas &amp;amp;&amp;amp; g_AgInk)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GetApp().ClearStatusBarMessage();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; loadPaths();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GetApp().DisplayStatusBarMessage("Waiting for Silverlight to initialize...", GrooveMessageBoxIcon_None );&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; window.setTimeout( tryLoadPaths, 100 );&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;function loadPaths()&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(g_AgCanvas.children)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Clear any existing paths from the canvas&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g_AgCanvas.children.clear();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xaml = GetHTMLFieldValue("Data");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(xaml)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var dom = new ActiveXObject("Microsoft.XMLDOM");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dom.loadXML(xaml);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var p = dom.documentElement;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for( var j=0; j&amp;lt;p.childNodes.length; j++ )&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var path = p.childNodes(j).xml;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; addPath(path);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch(e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; alert( "LoadPaths: " + e.description);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P mce_keep="true"&gt;There's one little wrinkle with the loader function:&amp;nbsp; Silverlight might not be ready yet.&amp;nbsp; This happens, for example,&amp;nbsp;when editing an existing Groove record:&amp;nbsp; Groove calls OnBeforeInitialize, we spin up the Silverlight control and have it load the initial canvas; Groove loads the data record, and calls the OnAfterInitialize form script, but Silverlight hasn't yet called back to say it's ready.&amp;nbsp; To avoid this case, I just set a little&amp;nbsp;timer (window.setTimeout) to try again a few milliseconds later.&lt;/P&gt;
&lt;P mce_keep="true"&gt;All done!&lt;/P&gt;
&lt;P&gt;&lt;IMG title=Silverlight! height=518 src="http://www.cabezal.com/msdnblog/20-silresult.png" width=775&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Here's the &lt;A class="" href="http://www.cabezal.com/msdnblog/Silverlight.gta" mce_href="http://www.cabezal.com/msdnblog/Silverlight.gta"&gt;tool template&lt;/A&gt;.&amp;nbsp; Use at your own risk, not production quality, no warranties and so on.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3447565" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>The Light of Day</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/12/01/the-light-of-day.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/12/01/the-light-of-day.aspx</id><published>2006-12-01T18:54:00Z</published><updated>2006-12-01T18:54:00Z</updated><content type="html">&lt;P&gt;Microsoft Office Groove 2007, Trial Product, in English and Spanish, for download.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://us1.trymicrosoftoffice.com/product.aspx?family=officelivegroove&amp;amp;culture=en-US"&gt;http://us1.trymicrosoftoffice.com/product.aspx?family=officelivegroove&amp;amp;culture=en-US&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1186130" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Forms Script: Send Instant Message</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/09/28/776280.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/09/28/776280.aspx</id><published>2006-09-28T17:47:00Z</published><updated>2006-09-28T17:47:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;I want to take you line-by-line through this code, with maybe a few words of explanation for each piece.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;// Find the contact&lt;BR&gt;&amp;nbsp;var pContact = GetContactFieldValue("Contact");&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Groove contacts are a datatype unto themselves; the contact object contains a ContactURL (the main unique identifier for this person's Groove identity; this is an opaque string), their VCard (with name, address, telephone numbers, email, and so on), and some internal stuff which provides enough information to allow Groove communicate with this user:&amp;nbsp; the URL of their relay server(s) and their public key.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;To send an instant message to a contact, you actually just need their contact URL, but the contact must be "known" as well:&amp;nbsp; in other words, although the API to send a message just wants the contact URL, it needs to look up that contact by URL in your account's database of known contacts, in order to send an encrypted message across the network to that user.&amp;nbsp; This "contact store" is a whole other subject, which I'm happy to delve into sometime.&amp;nbsp; But for now, the Contact field type gives us easy access to a known contact, and the contact's URL.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetContactFieldValue() is one of the built-in script functions.&amp;nbsp; In the Forms developer documentation (which is part of the &lt;/FONT&gt;&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=BAA487E9-E1B9-4A10-BEEA-1FD906B77F92&amp;amp;displaylang=en"&gt;&lt;FONT face=Arial size=2&gt;SDK&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt;), you can find the full list of public script functions; alternatively you can dive right in to the PublicFunctions.js script file which is located in Program Files\Microsoft Office\OFFICE12\Groove\ToolData\groove.net\GrooveForms5.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;if(!pContact)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;GetApp().DisplayError("Please specify a contact.");&lt;BR&gt;&amp;nbsp;&amp;nbsp;return;&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetContactFieldValue() returns the contact object (a IGrooveFormsToolContact) which is contained in the specified field.&amp;nbsp; If no contact has been selected, the return value is null, so we display an error message and return.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;To display the error message, I could have used "alert()", since the form page is just an Internet Explorer document.&amp;nbsp; But you get a nicer dialog box by using the DisplayError function.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetApp() returns the Forms tool's "UI delegate": the entrypoint into a collection of Groove-related functions and capabilities.&amp;nbsp; In this case, DisplayError is just a method on the UI delegate itself.&amp;nbsp; You can also access the other script interfaces and their functions by a syntax like, for example&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetApp().IGrooveFormsToolApplicationPreferences.DoesPreferenceExist("something")&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;For a full list of these other interfaces and functions, again, refer to the forms developer documentation in the SDK.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;if(!pContact.IsGroovey)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;GetApp().DisplayError("Please specify a Groove contact.");&lt;BR&gt;&amp;nbsp;&amp;nbsp;return;&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;We know we have a&amp;nbsp;IGrooveFormsToolContact object, and this is an extra safety check to ensure that the contact is "groovey": that the contact represents a Groove user, rather than just an email address or other contact who can't receive Groove instant messages.&amp;nbsp; It's actually quite hard to create non-groovey contacts in Groove 2007, but you might come across them occasionally.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;var enumContacts = CreateBSTREnumFromArray([pContact.ContactURL]);&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The pContact.ContactURL gives us the URL of the selected contact (which is a string).&amp;nbsp; Wrapping this in square brackets is JavaScript's syntax to create a single-element array.&amp;nbsp; Then we convert the script array into a BSTREnum, because the SendInstantMessage method we want to call later takes a IGrooveBSTREnum as the list of recipients.&amp;nbsp; A BSTREnum is an (unordered, strictly) enumeration of strings.&amp;nbsp; CreateBSTREnumFromArray() is one of the public script functions.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;// Get the message text&lt;BR&gt;&amp;nbsp;var sMessage = GetHTMLFieldValue("Message");&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Reads the text contents of the Message field into a string.&amp;nbsp; GetHTMLFieldValue() is another of the public script functions.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;nbsp;// Send message&lt;BR&gt;&amp;nbsp;GetApp().SendInstantMessage(enumContacts,sMessage);&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Sends an instant message, with the message body specified in sMessage, to the list of contacts in enumContacts.&amp;nbsp; The body is just plain text.&amp;nbsp; There are some optional parameters to this method, which we're just ignoring here: whether to track the message delivery, and whether to save the sent message into your message history.&amp;nbsp; There's also an interesting alternate method, SendInstantMessageWithLinks, which can embed Groove hyperlinks into the message.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;And that's it.&amp;nbsp; A simple form which sends instant messages when you press a button.&amp;nbsp; Extensions of this technique can be used to send messages automatically when a form is saved or particular conditions are met.&amp;nbsp; I hope this little walkthrough has covered a few of the not-completely-obvious ways in which Groove Forms script hangs together.&amp;nbsp; Let me know other subjects you'd like to see given the same treatment!&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=776280" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author><category term="Forms Tips" scheme="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx" /></entry><entry><title>Forms Script: Send Instant Message</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/09/28/775764.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/09/28/775764.aspx</id><published>2006-09-28T17:29:00Z</published><updated>2006-09-28T17:29:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;Sorry about the hiatus here.&amp;nbsp; It's been a while.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Here's a little piece of script code for Groove Forms, which might be useful to a few people.&amp;nbsp; It's also small enough to be a nice illustration of some of how script and forms work together.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The application itself is small enough to be nearly trivial: make a form with a button on it which sends an instant message to someone.&amp;nbsp; So, let's start with a new forms tool; create a contact field called "Contact", and a multi-line text field called "Message", and a script button called "Send".&amp;nbsp; In the designer, it looks like this:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;IMG SRC="http://www.cabezal.com/msdnblog/17-sendimform.PNG" width="478" height="451"&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;In the fields list, double-click the "Send" button-field to modify its properties; under "OnClick", enter a line of script code which calls a function we'll write in a second:&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;SendIM()&lt;/FONT&gt;&lt;/P&gt;
&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;And save.&amp;nbsp; Then, "Create new script", and paste in this script code.&lt;/FONT&gt;&lt;/P&gt;
&lt;div class="code"&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;function SendIM()&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;// Find the contact&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;var pContact = GetContactFieldValue("Contact");&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;if(!pContact)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetApp().DisplayError("Please specify a contact.");&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;return;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;if(!pContact.IsGroovey)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetApp().DisplayError("Please specify a Groove contact.");&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;return;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;var enumContacts = CreateBSTREnumFromArray([pContact.ContactURL]);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;// Get the message text&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;var sMessage = GetHTMLFieldValue("Message");&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;// Send message&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;GetApp().SendInstantMessage(enumContacts,sMessage);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/div&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Save.&amp;nbsp; Create a view.&amp;nbsp; Publish sandbox.&amp;nbsp; New -&amp;gt; Form, and test it out.&amp;nbsp; Everything should work: you can pick a contact in the contact field, write a message, and send the message to that contact.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Now let's look at how this all fits together.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=775764" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author><category term="Forms Tips" scheme="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx" /></entry><entry><title>Script Performance</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/08/30/731795.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/08/30/731795.aspx</id><published>2006-08-30T14:24:00Z</published><updated>2006-08-30T14:24:00Z</updated><content type="html">&lt;FONT face=Arial size=2&gt;If you're building anything complex with the Groove Forms tool, you probably use plenty of script code.&amp;nbsp; Peter Gurevich on the IE team has a &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/ie/archive/2006/08/28/728654.aspx"&gt;&lt;FONT face=Arial size=2&gt;great article&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt; about how to get the best performance.&amp;nbsp; I'm looking forward to parts two and three, too.&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=731795" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Office Developer Conference</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/08/02/686586.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/08/02/686586.aspx</id><published>2006-08-02T15:53:00Z</published><updated>2006-08-02T15:53:00Z</updated><content type="html">&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;MSDN have published &lt;A href="http://blogs.msdn.com/erikaehrli/archive/2006/07/28/officedeveloperconferencevideos.aspx"&gt;all&lt;/A&gt; the &lt;A href="http://msdn.microsoft.com/office/learn/conferences/default.aspx"&gt;session videos&lt;/A&gt; from the Office Developer Conference in March. This is the deepest presentation-type dive we've taken into Groove 2007 application development – and for three hours' attention you'll probably not find a better intro anywhere. In my humble opinion (-_-). &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;(The MSDN site's descriptions of CB302 and CB304 are switched around – they're correct below): &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;# &lt;A href="http://download.microsoft.com/download/4/a/5/4a599872-17bd-45f3-936a-4085da83d933/CB302_Pyle.wmv"&gt;CB302—Groove 2007: Developing Applications&lt;/A&gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Presenter: Hugh Pyle; 77 minutes (280 MB) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Get an overview of Groove and its application development environments: Groove Forms and InfoPath Forms for workgroup applications; Groove Web Services for programmatic access to Groove services and data; and the Groove Data Bridge systems integration platform. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;# &lt;A href="http://download.microsoft.com/download/4/a/5/4a599872-17bd-45f3-936a-4085da83d933/CB304_Mahoney.wmv"&gt;CB304—Groove 2007: Building Forms-Based Workgroup Applications&lt;/A&gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Presenter: Joshua Mahoney; 64 minutes (148 MB) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Learn how to use the Groove Forms and InfoPath Forms tools to build applications for team collaboration and structured data within Groove workspaces. &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;# &lt;A href="http://download.microsoft.com/download/4/a/5/4a599872-17bd-45f3-936a-4085da83d933/CB303_Pyle.wmv"&gt;CB303—Groove 2007: Web Services, Data Bridge and Systems Integration&lt;/A&gt; &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Presenter: Hugh Pyle; 72 minutes (275 MB) &lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: MS Shell Dlg"&gt;Learn how the Groove Web Services API provides programmers and professional developers access to the collaborative services of Groove 2007, including Groove Forms, InfoPath Forms, and files within Groove workspaces. &lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=686586" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>GWS and SharePoint</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/07/20/672682.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/07/20/672682.aspx</id><published>2006-07-20T13:41:00Z</published><updated>2006-07-20T13:41:00Z</updated><content type="html">&lt;A href="http://www.sharepointblogs.com/pm4everyone/default.aspx"&gt;&lt;FONT face=Arial size=2&gt;John Milan&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt;, from Bellevue-based &lt;/FONT&gt;&lt;A href="http://www.teamdirection.com/"&gt;&lt;FONT face=Arial size=2&gt;TeamDirection&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt;, is blogging about &lt;/FONT&gt;&lt;A href="http://www.sharepointblogs.com/pm4everyone/archive/2006/07/18/9316.aspx"&gt;&lt;FONT face=Arial size=2&gt;Groove and SharePoint&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt; integration using each product's web services APIs.&amp;nbsp; Worth keeping an eye on.&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=672682" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Files web service</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/07/06/658122.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/07/06/658122.aspx</id><published>2006-07-06T17:11:00Z</published><updated>2006-07-06T17:11:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;Let's move along quickly to the Files web service.&amp;nbsp; On the &lt;A href="http://www.microsoft.com/communities/newsgroups/list/en-us/default.aspx?dg=microsoft.public.groove"&gt;newsgroup&lt;/A&gt;, someone's been having problems creating files within folders in a Files tool, so this seems like good timing.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;A bit of background, first, to set the stage for some of the little complexities we'll probably come across later.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The Groove Files tool is a container for binary objects (files) in a folder tree.&amp;nbsp; There's a single root folder at the top of the tree, which you can't delete or rename. You can use web services methods to read the list of contents of a folder (recursively, or one level at a time), and to create, read, update and delete files and folders.&amp;nbsp; Events are provided so you can subscribe for notification when files/folders are modified in the tool.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Unlike the Forms tool, which is all about structured data, the Files tool doesn't have an extensible way for you to add custom metadata to a file or folder within the tool.&amp;nbsp; A file consists of a filename, some information about the creator/modifier, an ID, and maybe some file contents.&amp;nbsp; So, where you need extended metadata attached to binary objects, the Files tool might not be the ideal place to store that information within&amp;nbsp;a Groove workspace; you might find it more convenient to use a Forms tool with an Attachments field for the binary contents.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;On the other hand, Files tools have a couple of built-in features not available with Forms attachments:&amp;nbsp; binary-difference optimised change handling, and download-on-demand content.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Binary diffs are transparent to the user (and the application developer) but can make a substantial performance difference in bandwidth-constrained environments.&amp;nbsp; The diff process takes each update to a file and compares it to the previous version of the file's contents; if only a small region of the file has changed, then only those bits are sent across the network to other users.&amp;nbsp; (The tradeoff here is bandwidth against CPU.&amp;nbsp; If the diff is not much smaller than the original file, or if calculating the difference regions takes a while, then the whole file contents are sent instead).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Download-on-demand is controllable by users, and affects web services application developers too.&amp;nbsp; This feature (sometimes called "asymmetric files") separates the file stub (name, author, etc) from its contents; each member of the workspace can choose whether the actual file contents are downloaded to their machine.&amp;nbsp; This is set per folder, and the user interface has a few options:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.cabezal.com/msdnblog/16-asymmetricfiles.PNG"&gt;&lt;IMG height=329 src="http://www.cabezal.com/msdnblog/16-asymmetricfiles.PNG" width=417 border=0&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;As a developer, you'll see that asymmetric files are basically enabled all the time.&amp;nbsp; Every time you want to read a file's contents, you should check its download status first, otherwise you'll hit an exception.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=658122" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Newsreaders and code samples</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/06/28/649917.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/06/28/649917.aspx</id><published>2006-06-28T18:21:00Z</published><updated>2006-06-28T18:21:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;Sorry to anyone trying to make sense of these code samples with a newsreader; you'll miss all the formatting.&amp;nbsp; I should take a look at how &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/infopath/default.aspx"&gt;&lt;FONT face=Arial size=2&gt;these folks&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt; do it -- seems to work well for them.&amp;nbsp; Meanwhile, to see slightly-better-formatted code, you'll need to &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/hughpyle/default.aspx"&gt;&lt;FONT face=Arial size=2&gt;use a browser&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt;.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=649917" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Forms Attachments</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/06/28/649905.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/06/28/649905.aspx</id><published>2006-06-28T17:28:00Z</published><updated>2006-06-28T17:28:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;In Groove Forms, you can add an Attachments field to your forms, and store any number of attachments in the field.&amp;nbsp; (You can define more than one attachments field in the tool, but each form can only include one attachments field).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Let's look at accessing these attachments with web services.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Here's the schema of a form with one attachments field:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;lt;xs:complexType&amp;gt;&lt;BR&gt;&amp;lt;xs:sequence&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"Attachments\" type=\"FileAttachments\" minOccurs=\"0\" /&amp;gt;&lt;BR&gt;&amp;lt;!-- ... the other form fields ... --!&amp;gt;&lt;BR&gt;&amp;lt;/xs:sequence&amp;gt;&lt;BR&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The FileAttachments type is also defined in the schema; you can see the specification in Forms2.xsd in the development kit.&amp;nbsp; It consists of three linked types:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;An unbounded sequence of FileAttachment elements; each of which is...&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;A sequence of {ID, Created, CreatedBy, Modified, ModifiedBy, FullName, Type, Size, and Contents}, where Contents is...&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;A Base64 binary value.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;When you read this structure into&amp;nbsp;a DataSet, each of these types is represented as a separate table, with child relationships between the form, the FileAttachments, each FileAttachment, and its FileContents.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Convenient? Not without a small amount of code to wrap access to the attachments.&amp;nbsp; So let's write the code.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;My model here is to build a helper class which you can construct from a DataRow of forms data.&amp;nbsp; This helper should provide nice easy methods to enumerate existing file attachments, and to create and delete attachments too.&amp;nbsp; So here we go:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;class&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecord&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;private&lt;/FONT&gt; &lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt; _row;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#808080&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;///&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt; Construct a GrvFormsRecord from the DataRow representing the form data.&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; GrvFormsRecord(&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dataRow)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_row = dataRow;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;bool&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; SupportsAttachments&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;return&lt;/FONT&gt; (_row != &lt;FONT color=#0000ff&gt;null&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; &amp;amp;&amp;amp; _row.Table.ChildRelations.Count &amp;gt; 0);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;private&lt;/FONT&gt; &lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] AttachmentRows&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt;[] attachmentRows = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (SupportsAttachments)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForAttachProp = _row.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] attachPropRows = _row.GetChildRows(relationForAttachProp);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (attachPropRows.Length &amp;gt; 0)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; attachPropRow = attachPropRows[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (attachPropRow.Table.ChildRelations.Count &amp;gt; 0)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForFileAttach = attachPropRow.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;attachmentRows = attachPropRow.GetChildRows(relationForFileAttach);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;return&lt;/FONT&gt;&lt;FONT face=Arial&gt; attachmentRows;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The SupportsAttachments method is simple.&amp;nbsp; If the row doesn't define any child relationships, then your form doesn't include any FileAttachment-type fields, so you can't attach files to it.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Then there's a (private) getter to find the actual rows representing each file attachment.&amp;nbsp; This finds the single child row in the FileAttachments table, which represents the FileAttachments data type; then returns an array of all the FileAttachment child rows.&amp;nbsp; Each of these rows has columns for the attachment's metadata: FullName, Size, and so on.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;So far, so good.&amp;nbsp; Now it's easy to write this:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;int&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; AttachmentCount&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;return&lt;/FONT&gt;&lt;FONT face=Arial&gt; AttachmentRows.Length;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Next, I'll create a separate class to represent the attachment itself.&amp;nbsp; Once we have such an object, the rest of my&amp;nbsp;&lt;FONT color=#008080&gt;GrvFormsRecord&lt;/FONT&gt; class is easy too: provide an enumerator for attachments, and methods to create and delete attachments from the record.&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#008080&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#008080&gt;IEnumerable&lt;/FONT&gt;&amp;lt;&lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;&amp;gt; Attachments&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt; attachmentRow &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; AttachmentRows)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt; att = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;(attachmentRow);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;yield&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;return&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; att;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt; CreateAttachment(&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; name, &lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] content)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (!SupportsAttachments)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;throw&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;Exception&lt;/FONT&gt;(&lt;FONT color=#800000&gt;"Record does not support attachments."&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;return&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;(_row, name, content);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;void&lt;/FONT&gt; DeleteAttachment(&lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; att)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;att.Delete();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;And this makes the application-level code look really simple.&amp;nbsp; Something like this,&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;&lt;FONT color=#808080&gt;//&lt;/FONT&gt;&lt;FONT color=#008000&gt; Application code using GrvFormsRecord...&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; dr = formsDataTable.NewRow();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;GrvFormsRecord&lt;/FONT&gt; rec = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecord&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;(dr);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (rec.SupportsAttachments)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; fileName = &lt;FONT color=#008000&gt;// something.txt&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;[] fileContents = &lt;FONT color=#008000&gt;// the attachment contents&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;rec.CreateAttachment(fileName, fileContents);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;formsDataTable.Rows.Add(dr);&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;My&amp;nbsp;&lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/FONT&gt;&amp;nbsp;class wraps the attachment-metadata row and the related FileContents row into a single object.&amp;nbsp; Here I've made the constructors "internal", since the only way I want to create one of these objects is via the &lt;FONT color=#008080&gt;GrvFormsRecord&lt;/FONT&gt;&amp;nbsp;class above.&amp;nbsp; Without further explanation, then, here's the rest of the code.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; Helper class representing an attachment to a Forms record.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; Don't construct this directly; use the GrvFormsRecord class methods.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;/summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;class&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsRecordAttachment&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; _attachmentRow;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; _contentsRow;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Construct from an existing row&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;internal&lt;/FONT&gt; GrvFormsRecordAttachment(&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; attachmentRow)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow = attachmentRow;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForContent = _attachmentRow.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] contentRows = _attachmentRow.GetChildRows(relationForContent);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow = contentRows[0];&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Construct a new attachment from name and content&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;internal&lt;/FONT&gt; GrvFormsRecordAttachment(&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt; recordRow, &lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; name, &lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] content)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForAttachProp = recordRow.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] attachPropRows = recordRow.GetChildRows(relationForAttachProp);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; attachPropRow;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (attachPropRows.Length == 0)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataTable&lt;/FONT&gt;&lt;FONT face=Arial&gt; propertiesTable = relationForAttachProp.ChildTable;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;attachPropRow = propertiesTable.NewRow();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;propertiesTable.Rows.Add(attachPropRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;attachPropRow.SetParentRow(recordRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;else&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;attachPropRow = attachPropRows[0];&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Create the row in the FileAttachment table&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Note: the attachment's name is the FullName field.&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// in Groove V3.1 this was two properties, Name (filename with extension) and DisplayName (filename without extension)&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForFileAttach = attachPropRow.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataTable&lt;/FONT&gt;&lt;FONT face=Arial&gt; fileAttachmentTable = relationForFileAttach.ChildTable;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow = fileAttachmentTable.NewRow();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow[&lt;/FONT&gt;&lt;FONT face=Arial color=#800000&gt;"FullName"&lt;/FONT&gt;&lt;FONT face=Arial&gt;] = name;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow[&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#800000&gt;"Type"&lt;/FONT&gt;] = &lt;FONT color=#800000&gt;"File"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow[&lt;/FONT&gt;&lt;FONT face=Arial color=#800000&gt;"Size"&lt;/FONT&gt;&lt;FONT face=Arial&gt;] = content.Length;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.SetParentRow(attachPropRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;fileAttachmentTable.Rows.Add(_attachmentRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Create the row in the Contents table&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// and set the binary contents of the attachment&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRelation&lt;/FONT&gt;&lt;FONT face=Arial&gt; relationForContent = _attachmentRow.Table.ChildRelations[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataTable&lt;/FONT&gt;&lt;FONT face=Arial&gt; contentsTable = relationForContent.ChildTable;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow = contentsTable.NewRow();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_contentsRow[&lt;/FONT&gt;&lt;FONT face=Arial color=#800000&gt;"Base64"&lt;/FONT&gt;&lt;FONT face=Arial&gt;] = content;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow.SetParentRow(_attachmentRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;contentsTable.Rows.Add(_contentsRow);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Delete this attachment.&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;internal&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;void&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; Delete()&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow.Delete();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_contentsRow = &lt;/FONT&gt;&lt;FONT face=Arial color=#0000ff&gt;null&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.Delete();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow = &lt;/FONT&gt;&lt;FONT face=Arial color=#0000ff&gt;null&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; Filename of the attachment. Read-write.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;/summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; Name&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;return&lt;/FONT&gt; (&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;)_attachmentRow[&lt;FONT color=#800000&gt;"FullName"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;set&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.BeginEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow[&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#800000&gt;"FullName"&lt;/FONT&gt;] = &lt;FONT color=#0000ff&gt;value&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.EndEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; Size of the attachment, in bytes. Read-only.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;/summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;long&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; Size&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;return&lt;/FONT&gt; (&lt;FONT color=#0000ff&gt;long&lt;/FONT&gt;)_attachmentRow[&lt;FONT color=#800000&gt;"Size"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; The attachment contents. Read-write.&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;FONT color=#808080&gt;///&lt;/FONT&gt;&lt;FONT color=#008000&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;&amp;lt;/summary&amp;gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] Content&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;[] data = (&lt;FONT color=#0000ff&gt;byte&lt;/FONT&gt;[])_contentsRow[&lt;FONT color=#800000&gt;"Base64"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;return&lt;/FONT&gt;&lt;FONT face=Arial&gt; data;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;set&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.BeginEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_attachmentRow[&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#800000&gt;"Size"&lt;/FONT&gt;] = &lt;FONT color=#0000ff&gt;value&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;.Length;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.EndEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_attachmentRow.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow.BeginEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;_contentsRow[&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#800000&gt;"Base64"&lt;/FONT&gt;] = &lt;FONT color=#0000ff&gt;value&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow.EndEdit();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;_contentsRow.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;This pair of classes is simple and reusable enough to just drop in to any Forms-tool application projects, making forms attachments access a snap.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=649905" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>EnforceConstraints</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/06/28/649854.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/06/28/649854.aspx</id><published>2006-06-28T17:07:00Z</published><updated>2006-06-28T17:07:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;It's really nice to see people try using the techniques I'm posting here.&amp;nbsp; But, as usual, there are glitches when this stuff comes in contact with the real world.&amp;nbsp; Here's a really relevant comment from a user:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;"When I try to insert a new&amp;nbsp;DataRow to the first table of the Dataset (my Groove form)&amp;nbsp;I got an error since it says that the RecordURI is required. I'm confused since&amp;nbsp;I don't want to insert the RecordURI, the CreatedURL the modifiedURL etc..."&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;In &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/hughpyle/archive/2006/06/22/642954.aspx"&gt;&lt;FONT face=Arial size=2&gt;my code&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Arial size=2&gt; to create a DataSet from the RecordDataSet structure which is used by the GrooveForms2 service, there's a line which this user had missed out.&amp;nbsp; It says:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;recordDataSet.EnforceConstraints = &lt;FONT color=#0000ff&gt;false&lt;/FONT&gt;;&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Turns out, if you relax the DataSet's constraints, you can insert records just fine.&amp;nbsp; To understand why, let's look at the XML version of the schema for a very simple form&amp;nbsp;with only one text field:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&amp;lt;xs:complexType&amp;gt;&lt;BR&gt;&amp;lt;xs:sequence&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"MyFormsField\" type=\"xs:string\" minOccurs=\"0\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"RecordURI\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_ParentID\" type=\"xs:double\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_RecordID\" type=\"xs:double\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_Created\" type=\"xs:dateTime\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_CreatedBy\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_CreatedByURL\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_Modified\" type=\"xs:dateTime\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_ModifiedBy\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_ModifiedByURL\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"Forms_Tool_grooveFormID\" type=\"xs:double\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_Editors\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_Readers\" type=\"xs:string\" /&amp;gt;&lt;BR&gt;&amp;lt;xs:element name=\"_UnreadFlag\" type=\"xs:double\" /&amp;gt;&lt;BR&gt;&amp;lt;/xs:sequence&amp;gt;&lt;BR&gt;&amp;lt;/xs:complexType&amp;gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The user-defined field says &lt;EM&gt;minOccurs=0&lt;/EM&gt;.&amp;nbsp; All the system fields, on the other hand, don't have this; they are "required".&amp;nbsp; So the DataSet constraints prevent you from adding a row which doesn't specify values for the system fields.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;To which there are three possible solutions:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Relax constraints in the DataSet.&amp;nbsp; This is the recommended route.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Remove all the system columns from the DataSet before you insert rows.&amp;nbsp; This is a really good choice, since it reduces the amount of data sent in the SOAP packet when you insert or update records in the tool.&amp;nbsp; But it's slightly more work than just relaxing constraints.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Set arbitrary values in these fields.&amp;nbsp; Don't do this.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The bottom line: use &lt;SPAN class=code&gt;EnforceConstraints=false.&lt;/SPAN&gt;&amp;nbsp; It's safe and easy.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=649854" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Update Forms data</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/06/22/643145.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/06/22/643145.aspx</id><published>2006-06-22T18:22:00Z</published><updated>2006-06-22T18:22:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;Updating Forms data is just about as easy as creating new records:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Read the schema and the set of data which you want to update;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Update records in your DataSet with appropriate field values;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Call the Forms UpdateRecords() method to update the specified records.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;There are a few subtleties, though.&amp;nbsp; First of all: you don't always need to query for the records you'll be updating; if you already know their RecordURIs, that's enough.&amp;nbsp; So you might use something like this instead:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Know a list of RecordURIs which should be updated;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Read the schema of the form, constructing a DataSet with this schema but no records;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Create new records in your DataSet, each having a RecordURI and the new field values for that record;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Call the Forms UpdateRecords() method.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Secondly, if you don't want to update every field in a record, you really don't need to include the unchanged fields in the dataset parameter to UpdateRecords().&amp;nbsp; The update data set only needs to include, at a minimum, the RecordURI field and the fields which are being changed.&amp;nbsp; (This can lead to some performance benefits, if you're only updating one or two fields on a wide record).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;For example, if you want to set Status field to "Overdue" for all records whose "DueDate" value is in the past, you could implement like this:&amp;nbsp; removing the unnecessary columns will improve the performance of the web services call.&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Query (for schema and data) where String.Format("DueDate&amp;nbsp;&amp;lt; #{0}#", nowstring);&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Update records in the DataSet with new values for the Status field;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Remove un-needed columns from the table's schema;&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Call the Forms UpdateRecords() method.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial&gt;&lt;FONT size=2&gt;&lt;STRONG&gt;NOTE&lt;/STRONG&gt;: &lt;STRONG&gt;None of these examples are transactionally safe&lt;/STRONG&gt;.&amp;nbsp; You're making two separate web services calls: one to retrieve a set of data (or their RecordURIs), and another to update those records.&amp;nbsp; In between those two calls, the data might have changed: field values might be different already, or the records might have been deleted, or other records might have been created in the tool which you don't know about yet.&amp;nbsp; Groove Web Services doesn't include any mechanisms to create a "lock" on the data across multiple calls, so you need to use some appropriate defensive strategy.&amp;nbsp; I should blog about some approaches for dealing with this type of update "safely", but that&amp;nbsp;will have to wait for another day.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Anyhow; here's some code.&amp;nbsp; First, my Update method in my helper class:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class="code"&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;void&lt;/FONT&gt; Update(System.Data.&lt;FONT color=#008080&gt;DataSet&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dataSet)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (!IsDesignInitialized)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;throw&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;Exception&lt;/FONT&gt;(&lt;FONT color=#800000&gt;"Forms tool design is not initialized."&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;GrooveForms2WebService.&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;Forms2RecordDataSet&lt;/FONT&gt; formsDs = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; GrooveForms2WebService.&lt;FONT color=#008080&gt;Forms2RecordDataSet&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;dataSet.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;string&lt;/FONT&gt;&lt;FONT face=Arial&gt; str = dataSet.GetXmlSchema();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlDocument&lt;/FONT&gt; xmlDoc = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlDocument&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;xmlDoc.LoadXml(str);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;[] schemaArray = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[1];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;schemaArray[0] = xmlDoc.DocumentElement;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;formsDs.Schema = schemaArray;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;str = dataSet.GetXml();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;xmlDoc.LoadXml(str);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;XmlNodeList&lt;/FONT&gt;&lt;FONT face=Arial&gt; nodelist = xmlDoc.DocumentElement.ChildNodes;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;[] dataArray = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[nodelist.Count];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;int&lt;/FONT&gt;&lt;FONT face=Arial&gt; j = 0;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;XmlNode&lt;/FONT&gt; node &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; nodelist)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;dataArray[j] = (&lt;/FONT&gt;&lt;FONT face=Arial color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;FONT face=Arial&gt;)node;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;j++;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;formsDs.Data = dataArray;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;GrooveForms2WebService.&lt;/FONT&gt;&lt;FONT face=Arial color=#008080&gt;GrooveForms2&lt;/FONT&gt;&lt;FONT face=Arial&gt; svc = GetDataService();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;svc.UpdateRecords(formsDs, &lt;FONT color=#0000ff&gt;true&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Then a short example following the third approach above, to set a Status field.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class="code"&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;GrvFormsTool&lt;/FONT&gt; tool = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsTool&lt;/FONT&gt;( . . . . &lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Query for overdue records&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; nowstring = &lt;FONT color=#008080&gt;DateTime&lt;/FONT&gt;.Now.ToUniversalTime().ToString(&lt;FONT color=#800000&gt;"yyyy'-'MM'-'ddTHH':'mm':'ss'.'fff'Z'"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; query = &lt;FONT color=#008080&gt;String&lt;/FONT&gt;.Format(&lt;FONT color=#800000&gt;"DueDate &amp;lt; #{0}#"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;, nowstring);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataSet&lt;/FONT&gt;&lt;FONT face=Arial&gt; ds = tool.Query(query);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (ds.Tables.Count &amp;gt; 0)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Assume we already know which form (==table)&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataTable&lt;/FONT&gt;&lt;FONT face=Arial&gt; dt = ds.Tables[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Set the status field on each row&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;DataRow&lt;/FONT&gt; dr &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dt.Rows)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;dr[&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#800000&gt;"Status"&lt;/FONT&gt;] = &lt;FONT color=#800000&gt;"Overdue"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Remove columns other than Status and RecordURI&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&amp;gt; columnsToDelete = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;&amp;gt;();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;DataColumn&lt;/FONT&gt; dc &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dt.Columns)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;string&lt;/FONT&gt;&lt;FONT face=Arial&gt; cn = dc.ColumnName;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;if&lt;/FONT&gt; (cn != &lt;FONT color=#800000&gt;"RecordURI"&lt;/FONT&gt; &amp;amp;&amp;amp; cn != &lt;FONT color=#800000&gt;"Status"&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;columnsToDelete.Add(cn);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt; c &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; columnsToDelete)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;dt.Columns.Remove(c);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;dt.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;tool.Update(ds);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;(OK, I'm sure there are more concise ways to deal with a DataSet than this.&amp;nbsp; My ignorance is all over.)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;That caveat, again: this is not transactionally safe, so all sorts of things might happen 'twixt query and update.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=643145" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry><entry><title>Insert Forms data</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/hughpyle/archive/2006/06/22/643098.aspx" /><id>http://blogs.msdn.com/hughpyle/archive/2006/06/22/643098.aspx</id><published>2006-06-22T17:55:00Z</published><updated>2006-06-22T17:55:00Z</updated><content type="html">&lt;P&gt;&lt;FONT face=Arial size=2&gt;It's quite straightforward to create new Forms records:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Read the Forms tool's schema into a DataSet;&lt;/FONT&gt; 
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Add new records to the DataSet with appropriate field values;&lt;/FONT&gt; 
&lt;LI&gt;&lt;FONT face=Arial size=2&gt;Call the Forms CreateRecords() method to insert the new records.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;A single call to CreateRecords() will insert as many new records as contained in your dataset; you don't need to make a separate call for each one.&amp;nbsp; (It's quite a lot more efficient to create multiple records at once).&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Here's&amp;nbsp;the code I use to make an Insert() method in my wrapper class.&amp;nbsp; It takes a System.Data.DataSet, writes its schema and data to the GrooveForms2WebService RecordDataSet, and calls the CreateRecords() method on the web service:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT color=#0000ff&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;public&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;[] Insert(System.Data.&lt;FONT color=#008080&gt;DataSet&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dataSet)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (!IsDesignInitialized)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;throw&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;Exception&lt;/FONT&gt;(&lt;FONT color=#800000&gt;"Forms tool design is not initialized."&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;GrooveForms2WebService.&lt;/FONT&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;Forms2RecordDataSet&lt;/FONT&gt; formsDs = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; GrooveForms2WebService.&lt;FONT color=#008080&gt;Forms2RecordDataSet&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;dataSet.AcceptChanges();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;string&lt;/FONT&gt;&lt;FONT face=Arial&gt; str = dataSet.GetXmlSchema();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlDocument&lt;/FONT&gt; xmlDoc = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlDocument&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;xmlDoc.LoadXml(str);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;[] schemaArray = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[1];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;schemaArray[0] = xmlDoc.DocumentElement;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;formsDs.Schema = schemaArray;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;str = dataSet.GetXml();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;xmlDoc.LoadXml(str);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;XmlNodeList&lt;/FONT&gt;&lt;FONT face=Arial&gt; nodelist = xmlDoc.DocumentElement.ChildNodes;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;[] dataArray = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[nodelist.Count];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;int&lt;/FONT&gt;&lt;FONT face=Arial&gt; j = 0;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;XmlNode&lt;/FONT&gt; node &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; nodelist)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;dataArray[j] = (&lt;/FONT&gt;&lt;FONT face=Arial color=#008080&gt;XmlElement&lt;/FONT&gt;&lt;FONT face=Arial&gt;)node;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;j++;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;formsDs.Data = dataArray;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;GrooveForms2WebService.&lt;/FONT&gt;&lt;FONT face=Arial color=#008080&gt;GrooveForms2&lt;/FONT&gt;&lt;FONT face=Arial&gt; svc = GetDataService();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;return&lt;/FONT&gt;&lt;FONT face=Arial&gt; svc.CreateRecords(formsDs);&lt;/FONT&gt;&lt;/FONT&gt; 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT face=Arial size=2&gt;The return value is an array of RecordURIs of the newly-created records.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;To call this, here's an example setting text fields to random values, in 100 new records:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#008080&gt;GrvFormsTool&lt;/FONT&gt; tool = &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;GrvFormsTool&lt;/FONT&gt;( . . . .&lt;/FONT&gt;&lt;FONT face=Arial&gt;);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Construct a DataSet matching the tool's schema&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataSet&lt;/FONT&gt;&lt;FONT face=Arial&gt; ds = tool.GetSchema();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (ds.Tables.Count &amp;gt; 0)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// First table in the DataSet corresponds to the first form&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// (you should usually open the table by name...!)&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataTable&lt;/FONT&gt;&lt;FONT face=Arial&gt; dt = ds.Tables[0];&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;&lt;FONT face=Arial size=2&gt;// Insert 100 records with text fields set to random values&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;for&lt;/FONT&gt; (&lt;FONT color=#0000ff&gt;int&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; j = 0; j &amp;lt; 100; j++)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#008080&gt;DataRow&lt;/FONT&gt;&lt;FONT face=Arial&gt; dr = dt.NewRow();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;foreach&lt;/FONT&gt; (&lt;FONT color=#008080&gt;DataColumn&lt;/FONT&gt; c &lt;FONT color=#0000ff&gt;in&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt; dt.Columns)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#0000ff&gt;if&lt;/FONT&gt;&lt;FONT face=Arial&gt; (!ReservedFormsFields.Contains(c.ColumnName))&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;if&lt;/FONT&gt; (c.DataType &lt;FONT color=#0000ff&gt;is&lt;/FONT&gt; &lt;FONT color=#008080&gt;String&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;)&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;dr[c] = &lt;/FONT&gt;&lt;FONT face=Arial color=#008080&gt;Guid&lt;/FONT&gt;&lt;FONT face=Arial&gt;.NewGuid().ToString();&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;dt.Rows.Add(dr);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;tool.Insert(ds);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Of course I'm expecting you already know which fields you want to set.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Note that the record's schema includes several "internal" fields, which you generally don't want to write values for (they'll be assigned automatically by Groove as appropriate).&amp;nbsp; Some of these fields are writable in some circumstances: _CreatedByURL can be set when a new record is created, for example, but is read-only thereafter.&amp;nbsp; There's more documentation in the SDK.&amp;nbsp; In this example I've wrapped this list of reserved fields in a small static helper property:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;private&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;static&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;[] _excl = {&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"RecordURI"&lt;/FONT&gt;&lt;FONT face=Arial&gt;, &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_RecordID"&lt;/FONT&gt;&lt;FONT face=Arial&gt;, &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_ParentID"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_Modified"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_ModifiedBy"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_ModifiedByURL"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_Created"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_CreatedBy"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_CreatedByURL"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_Editors"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_Readers"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_IgnoreUnread"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"_UnreadFlag"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"Forms_Tool_grooveFormID"&lt;/FONT&gt;&lt;FONT face=Arial&gt;,&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial color=#800000&gt;"Forms_Tool_IPContents"&lt;/FONT&gt;&lt;FONT face=Arial&gt; };&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;private&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;static&lt;/FONT&gt; &lt;FONT color=#008080&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;&amp;gt; ReservedFormsFields&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT face=Arial size=2&gt;get&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;{&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;&lt;FONT face=Arial&gt;&lt;FONT color=#0000ff&gt;return&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;new&lt;/FONT&gt; &lt;FONT color=#008080&gt;List&lt;/FONT&gt;&amp;lt;&lt;FONT color=#0000ff&gt;string&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Arial&gt;&amp;gt;(_excl);&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=643098" width="1" height="1"&gt;</content><author><name>hpyle</name><uri>http://blogs.msdn.com/members/hpyle.aspx</uri></author></entry></feed>