<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>hughpyle : Forms Tips</title><link>http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx</link><description>Tags: Forms Tips</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Forms Script: Send Instant Message</title><link>http://blogs.msdn.com/hughpyle/archive/2006/09/28/776280.aspx</link><pubDate>Thu, 28 Sep 2006 20:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:776280</guid><dc:creator>hpyle</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/hughpyle/comments/776280.aspx</comments><wfw:commentRss>http://blogs.msdn.com/hughpyle/commentrss.aspx?PostID=776280</wfw:commentRss><description>&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;</description><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx">Forms Tips</category></item><item><title>Forms Script: Send Instant Message</title><link>http://blogs.msdn.com/hughpyle/archive/2006/09/28/775764.aspx</link><pubDate>Thu, 28 Sep 2006 20:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:775764</guid><dc:creator>hpyle</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/hughpyle/comments/775764.aspx</comments><wfw:commentRss>http://blogs.msdn.com/hughpyle/commentrss.aspx?PostID=775764</wfw:commentRss><description>&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;</description><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx">Forms Tips</category></item><item><title>Reading Forms Data</title><link>http://blogs.msdn.com/hughpyle/archive/2005/09/09/454754.aspx</link><pubDate>Fri, 09 Sep 2005 21:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:454754</guid><dc:creator>hpyle</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/hughpyle/comments/454754.aspx</comments><wfw:commentRss>http://blogs.msdn.com/hughpyle/commentrss.aspx?PostID=454754</wfw:commentRss><description>&lt;P&gt;&lt;FONT face=Arial size=2&gt;I think we can read Forms data now.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1&gt;&lt;FONT face=Arial size=2&gt;We already added event handlers to two of our three combo-boxes (IdentitiesCombo, WorkspacesCombo), so let's do the same for the ToolsCombo, which contains a list of tools in the selected workspace.&amp;nbsp; When the selection changes, we should read data from the tool.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;private&lt;/FONT&gt;&lt;FONT size=1&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;void&lt;/FONT&gt;&lt;FONT size=1&gt; ToolsCombo_SelectedIndexChanged(&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;object&lt;/FONT&gt;&lt;FONT size=1&gt; sender, &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;EventArgs&lt;/FONT&gt;&lt;FONT size=1&gt; e)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Each item in the combobox is a ToolInfo, containing a Groove Tool&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;ToolInfo&lt;/FONT&gt;&lt;FONT size=1&gt; t = (&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;ToolInfo&lt;/FONT&gt;&lt;FONT size=1&gt;)ToolsCombo.SelectedItem;&lt;/P&gt;
&lt;P&gt;ReadDataFromTool(t.tool);&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;To display the data, let's drop a DataGridView into the form, and make it read-only.&amp;nbsp; (&lt;A href="http://www.windowsforms.net/WhidbeyFeatures/default.aspx?PageID=2&amp;amp;ItemID=13&amp;amp;Cat=Controls&amp;amp;tabindex=5"&gt;DataGridView&lt;/A&gt; is new with Visual Studio 2005; if you're using Visual Studio 2003, a DataGrid is just as good).&amp;nbsp; Then, when we have some data, let's assume we also have a DataSet.&amp;nbsp;&amp;nbsp; The only magic piece here is that the data set will need a particular name ("RecordDataSet"), because that's the name we'll receive from Groove.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT size=1&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;&lt;FONT color=#0000ff size=1&gt;
&lt;P&gt;private&lt;/FONT&gt;&lt;FONT color=#000000 size=1&gt; &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;void&lt;/FONT&gt;&lt;FONT color=#000000 size=1&gt; ReadDataFromTool(&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;Tool&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;FONT color=#000000&gt; t)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;// Make a DataSet to contain the records&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;System.Data.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;DataSet&lt;/FONT&gt;&lt;FONT size=1&gt; recordDataSet = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; System.Data.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;DataSet&lt;/FONT&gt;&lt;FONT size=1&gt;(&lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"RecordDataSet"&lt;/FONT&gt;&lt;FONT size=1&gt;);&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// ... Get some data ...&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Bind the dataset to the grid view&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;dataGridView1.ReadOnly = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;true&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;dataGridView1.DataSource = recordDataSet.Tables[0];&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Without further comment, let's just read data.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT face=Arial size=2&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// The Tool has a web service URI for us to access its data via the GrooveForms service&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;string&lt;/FONT&gt;&lt;FONT size=1&gt; toolURI = t.Data;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveForms&lt;/FONT&gt;&lt;FONT size=1&gt; formsService = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveForms&lt;/FONT&gt;&lt;FONT size=1&gt;();&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; GrooveFormsWebService.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveRequestHeader&lt;/FONT&gt;&lt;FONT size=1&gt;();&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue.GrooveRequestKey = &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GWSUtil&lt;/FONT&gt;&lt;FONT size=1&gt;.GrooveLocalRequestKey;&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue.GrooveIdentityURL = selectedIdentity.URI;&lt;/P&gt;
&lt;P&gt;formsService.Url = &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GWSUtil&lt;/FONT&gt;&lt;FONT size=1&gt;.GrooveURL + toolURI;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Query for all the records, no attachments&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;GrooveFormsWebService.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;RecordQuery&lt;/FONT&gt;&lt;FONT size=1&gt; recordQuery = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; GrooveFormsWebService.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;RecordQuery&lt;/FONT&gt;&lt;FONT size=1&gt;();&lt;/P&gt;
&lt;P&gt;recordQuery.FieldSchemaScopingElement = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;""&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.FieldSchemaScopingFlag = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"All"&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.FileAttachmentFormat = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"Base64"&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.FormURI = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;""&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.IncludeFileAttachmentContent = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;false&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.QueryMetadataOnly = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;false&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.UnreadRecordsOnly = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;false&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.ViewURI = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;""&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;recordQuery.WhereClause = &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;""&lt;/FONT&gt;&lt;FONT size=1&gt;;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Ask service to query records&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;FormsRecordDataSet&lt;/FONT&gt;&lt;FONT size=1&gt; fds = formsService.QueryRecords(recordQuery);&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;And we end up with a FormsRecordDataSet, which is a serialized set of Groove Forms data retrieved from the web service.&amp;nbsp; In this case we called QueryRecords(), which is a very flexible way to retrieve some or all records in a tool; it can include a WhereClause with some SQL-like syntax:&amp;nbsp; a conditional expression or a series of conditional expressions joined by AND and OR logical operators (and parentheses), with the usual comparison operators, "LIKE" and "NOT LIKE".&amp;nbsp; (The full documentation for this is in the API reference in the &lt;A href="http://www.groove.net/solutions/develop/downloads.cfm"&gt;Groove Web Services GDK&lt;/A&gt;).&amp;nbsp; To read a known subset of the data, an alternative to QueryRecords() would be ReadRecords(), which takes a list of record URIs for specific records.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The FormsRecordDataSet arrived in a SOAP packet as a chunk of XML, and it turns out that the XML format for this is designed to be essentially the same as a System.Data.DataSet serialization;&amp;nbsp; there's an array of&amp;nbsp;schema nodes, and an array of data nodes.&amp;nbsp; So we can push that XML into our DataSet quite easily:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT face=Arial size=2&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// If schema exists, load it into the DataSet&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;if&lt;/FONT&gt;&lt;FONT size=1&gt; (fds.Schema &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;is&lt;/FONT&gt;&lt;FONT size=1&gt; System.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;Array&lt;/FONT&gt;&lt;FONT size=1&gt;)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// For Groove V3 it's safe to assume there is only one schema in the dataset (although this may change)&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt;[] schemaNodes = (System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt;[])fds.Schema;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;foreach&lt;/FONT&gt;&lt;FONT size=1&gt; (System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt; schemaNode &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;in&lt;/FONT&gt;&lt;FONT size=1&gt; schemaNodes)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;System.IO.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;StringReader&lt;/FONT&gt;&lt;FONT size=1&gt; schemaReader = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; System.IO.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;StringReader&lt;/FONT&gt;&lt;FONT size=1&gt;(&lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"&amp;lt;?xml version=\"1.0\"?&amp;gt;"&lt;/FONT&gt;&lt;FONT size=1&gt; + schemaNode.OuterXml);&lt;/P&gt;
&lt;P&gt;recordDataSet.ReadXmlSchema(schemaReader);&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// If data exists, load it into the DataSet&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;if&lt;/FONT&gt;&lt;FONT size=1&gt; (fds.Data &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;is&lt;/FONT&gt;&lt;FONT size=1&gt; System.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;Array&lt;/FONT&gt;&lt;FONT size=1&gt;)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt;[] dataNodes = (System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt;[])fds.Data;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;foreach&lt;/FONT&gt;&lt;FONT size=1&gt; (System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNode&lt;/FONT&gt;&lt;FONT size=1&gt; dataNode &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;in&lt;/FONT&gt;&lt;FONT size=1&gt; dataNodes)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNodeReader&lt;/FONT&gt;&lt;FONT size=1&gt; dataReader = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; System.Xml.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlNodeReader&lt;/FONT&gt;&lt;FONT size=1&gt;(dataNode);&lt;/P&gt;
&lt;P&gt;recordDataSet.ReadXml(dataReader, System.Data.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;XmlReadMode&lt;/FONT&gt;&lt;FONT size=1&gt;.Auto);&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;And we're done!&amp;nbsp; Because the FormsRecordDataSet includes its own schema, and the DataSet knows how to parse a schema in XML format, there's no need to wrestle with individual columns and their datatypes; it just drops right in.&amp;nbsp; Then when bound to the DataGridView, we see Groove data in the form.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Copy, paste, build, run.&amp;nbsp; Outlook shows my menu-button, and when I click the button, here's the form:&lt;/FONT&gt;&lt;/P&gt;&lt;IMG src="http://www.cabezal.com/msdnblog/13-dataform.PNG"&gt; 
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Wasn't that easy?&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=454754" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Demo/default.aspx">Forms Demo</category><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx">Forms Tips</category></item><item><title>Identifying Groove Forms Tools</title><link>http://blogs.msdn.com/hughpyle/archive/2005/09/09/454753.aspx</link><pubDate>Fri, 09 Sep 2005 21:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:454753</guid><dc:creator>hpyle</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/hughpyle/comments/454753.aspx</comments><wfw:commentRss>http://blogs.msdn.com/hughpyle/commentrss.aspx?PostID=454753</wfw:commentRss><description>&lt;P&gt;&lt;FONT face=Arial size=2&gt;The various workspace tools each have a Type, which identifies the tool:&amp;nbsp; Files, Discussion, Calendar, Forms, and so on.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The standard list of tool types in Groove V3 are:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT size=1&gt;
&lt;P&gt;urn:groove.net:platform.tools.Forms&lt;/P&gt;
&lt;P&gt;urn:groove.net:platform.tools.Files&lt;/P&gt;
&lt;P&gt;urn:groove.net:platform.tools.Discussion&lt;/P&gt;
&lt;P&gt;urn:groove.net:platform.tools.Calendar&lt;/P&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Within a Forms tool, the designer may also have specified a DesignName and DesignVersion; these are optional, but I'd strongly recommend you use them to label your tools.&amp;nbsp; The design name is a URN.&amp;nbsp; The design version is just a string, but I recommend choosing a "dotted numbers" format: at a minimum &amp;lt;majorversion&amp;gt;.&amp;lt;minorversion&amp;gt;.&amp;nbsp; That way, it's easy to identify releases of the same tool with compatible schemas (same major-version) or incompatible schemas (different major-version), and to write code to handle your various versions appropriately.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;I went back and added a nice long design-name, and a version number,&amp;nbsp;to the &lt;/FONT&gt;&lt;a href="http://blogs.msdn.com/hughpyle/archive/2005/07/22/441808.aspx"&gt;&lt;FONT face=Arial size=2&gt;Forms tool from earlier&lt;/FONT&gt;&lt;/A&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;IMG src="http://www.cabezal.com/msdnblog/12-designname.PNG"&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;Now, our GWS application currently list all workspace tools in the tools combo-box.&amp;nbsp; This can easily be reduced to only display Forms tools, by checking the tool's type:&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT face=Arial size=2&gt;&lt;FONT color=#008080 size=1&gt;
&lt;P&gt;Tool&lt;/FONT&gt;&lt;FONT size=1&gt;[] tools = toolsService.Read();&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Add the tools to the combobox (unselected).&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT color=#008000 size=1&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;foreach&lt;/FONT&gt;&lt;FONT size=1&gt; (&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;Tool&lt;/FONT&gt;&lt;FONT size=1&gt; t &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;in&lt;/FONT&gt;&lt;FONT size=1&gt; tools) 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Only add the tool to the list if it's a Forms tool&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT color=#008000 size=1&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;if&lt;/FONT&gt;&lt;FONT size=1&gt; (t.Type == &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"urn:groove.net:platform.tools.Forms"&lt;/FONT&gt;&lt;FONT size=1&gt;) 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;{&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/P&gt;
&lt;P&gt;ToolsCombo.Items.Add(&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;ToolInfo&lt;/FONT&gt;&lt;FONT size=1&gt;(t));&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;We want to further restrict this to only include Forms tools with the design-name we chose.&amp;nbsp; Only those tools will have the correct schema, and the data-transfer portion of my little application will be hard-coded to only expect the fields I created in that forms tool.&amp;nbsp; The code for this is slightly more involved, because DesignName isn't a property on the Tool; it's a property on a ToolProperties class, which requires one extra web-services call to Groove.&lt;/FONT&gt;&lt;/P&gt;
&lt;DIV class=code&gt;&lt;FONT face=Arial size=2&gt;&lt;FONT color=#008080 size=1&gt;
&lt;P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#008000 size=1&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;if&lt;/FONT&gt;&lt;FONT size=1&gt; (t.Type == &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"urn:groove.net:platform.tools.Forms"&lt;/FONT&gt;&lt;FONT size=1&gt;) 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Query the forms tool to find its "design name"&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// (property set by the forms designer).&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// The contacts tool we can connect with has a known type (which we made up):&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// urn:groove.net:pdc2005.demonstration.Contacts&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;// Only add these special tools to the tools combobox.&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;string&lt;/FONT&gt;&lt;FONT size=1&gt; toolURI = t.Data;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveForms&lt;/FONT&gt;&lt;FONT size=1&gt; formsService = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveForms&lt;/FONT&gt;&lt;FONT size=1&gt;();&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue = &lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; GrooveFormsWebService.&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GrooveRequestHeader&lt;/FONT&gt;&lt;FONT size=1&gt;();&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue.GrooveRequestKey = &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GWSUtil&lt;/FONT&gt;&lt;FONT size=1&gt;.GrooveLocalRequestKey;&lt;/P&gt;
&lt;P&gt;formsService.GrooveRequestHeaderValue.GrooveIdentityURL = selectedIdentity.URI;&lt;/P&gt;
&lt;P&gt;formsService.Url = &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;GWSUtil&lt;/FONT&gt;&lt;FONT size=1&gt;.GrooveURL + toolURI;&lt;/P&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;ToolProperties&lt;/FONT&gt;&lt;FONT size=1&gt; tp = formsService.ReadToolProperties();&lt;/FONT&gt;&lt;FONT color=#008000 size=1&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;
&lt;P&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;if&lt;/FONT&gt;&lt;FONT size=1&gt; (tp.DesignTemplateName == &lt;/FONT&gt;&lt;FONT color=#800000 size=1&gt;"urn:groove.net:pdc2005.demonstration.Contacts"&lt;/FONT&gt;&lt;FONT size=1&gt;)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;P&gt;ToolsCombo.Items.Add(&lt;/FONT&gt;&lt;FONT color=#0000ff size=1&gt;new&lt;/FONT&gt;&lt;FONT size=1&gt; &lt;/FONT&gt;&lt;FONT color=#008080 size=1&gt;ToolInfo&lt;/FONT&gt;&lt;FONT size=1&gt;(t));&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face=Arial size=2&gt;The behaviour of our application, once this code is added, isn't really optimal:&amp;nbsp; you're presented with a list of workspaces, even those which don't contain any matching tools.&amp;nbsp; Doing this "properly" is left as an exercise to the reader :-)&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=454753" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Demo/default.aspx">Forms Demo</category><category domain="http://blogs.msdn.com/hughpyle/archive/tags/Forms+Tips/default.aspx">Forms Tips</category></item></channel></rss>