<?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>David Kline : GUI</title><link>http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx</link><description>Tags: GUI</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Quick Tip: Getting the Collection of Checked ListView Items</title><link>http://blogs.msdn.com/davidklinems/archive/2007/06/18/quick-tip-getting-the-collection-of-checked-listview-items.aspx</link><pubDate>Mon, 18 Jun 2007 21:09:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3387821</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/3387821.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=3387821</wfw:commentRss><description>&lt;P&gt;Have you ever created a ListView control and wanted to get the collection of items that the user has checked?&amp;nbsp; While I was working on my demo for MEDC, that was one of the things that I needed to be able to do.&amp;nbsp; If I were writing my application for the .NET Framework, I would get the collection of items via the ListView.CheckedItems property.&amp;nbsp; When I looked up ListView in the MSDN documentation, I found that the CheckedItems property is not supported on the &lt;A href="http://blogs.msdn.com/netcfteam" mce_href="http://blogs.msdn.com/netcfteam"&gt;.NET Compact Framework&lt;/A&gt;.&amp;nbsp; As a result, I was going to need to create the collection myself.&amp;nbsp; Or was I?&lt;BR&gt;&lt;BR&gt;Since the application that I was writing was a demonstration of the cool new features of .NET Compact Framework version 3.5, I decided to try my hand a using Language Integrated Query, specifically LINQ to Objects.&amp;nbsp; The resulting code was small, worked well and was quite easy to read.&amp;nbsp; Let's take a look at what I wrote.&lt;BR&gt;&lt;CODE&gt;&lt;BR&gt;public static List&amp;lt;ListViewItem&amp;gt; GetCheckedListViewItems(ListView lv)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;ListViewItem&amp;gt; checkedItems = (from ListViewItem lvi in lv.Items&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;&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;where (true == lvi.Checked)&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;&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;select lvi).ToList();&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return checkedItems;&lt;BR&gt;}&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;The method above is based on my Lunch Launcher demo application, as shown during the What's New in .NET Compact Framework version 3.5 session that I delivered at MEDC 2007 last month.&amp;nbsp;&amp;nbsp; How does it work?&amp;nbsp; First, we specify that we are interested in the ListViewItem objects contained within the ListView.Items property.&lt;BR&gt;&lt;CODE&gt;&lt;BR&gt;from ListViewItem lvi in lv.Items&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Next, we define the condition under which we are interested in the item, in our case when the item has been checked by the user.&lt;BR&gt;&lt;CODE&gt;&lt;BR&gt;where (true == lvi.Checked)&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Then we select the item.&lt;BR&gt;&lt;CODE&gt;&lt;BR&gt;select lvi&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Lastly, we call the ToList method to have the selected items returned to us as a List&amp;lt;ListViewItem&amp;gt;.&lt;BR&gt;&lt;BR&gt;Pretty neat and much nicer to read than a foreach loop.&amp;nbsp; If you have installed the &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=1343d537-a62f-4a6e-9727-7791bf4cc2bd&amp;amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=1343d537-a62f-4a6e-9727-7791bf4cc2bd&amp;amp;DisplayLang=en"&gt;beta of .NET Compact Framework version 3.5&lt;/A&gt;, give LINQ a try and see how it can make your applications easier to write.&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK&lt;BR&gt;&lt;BR&gt;&lt;FONT face=Arial size=1&gt;[Edit: fix formatting]&lt;BR&gt;&lt;BR&gt;Disclaimers:&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;BR&gt;The information contained within this post is in relation to beta software.&amp;nbsp; Any and all details are subject to change.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3387821" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Quick+Tips/default.aspx">Quick Tips</category></item><item><title>Separating Application Logic and Data Presentation layers</title><link>http://blogs.msdn.com/davidklinems/archive/2006/10/05/Separating-Application-Logic-and-Data-Presentation-layers.aspx</link><pubDate>Fri, 06 Oct 2006 00:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:794721</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/794721.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=794721</wfw:commentRss><description>I'm a big advocate of separating an application's logic from it's user interface.&amp;nbsp; By keeping the logic separate from the data presentation layer (UI), it becomes easy to swap out either component with minimal impact on the other.&amp;nbsp; In addition to ease of replacing components, keeping the user interface separate from the application logic avoids blocking the UI during expensive operations.&lt;BR&gt;&lt;BR&gt;Today, I'm going to revisit the .NET Compact Framework WebCrawler sample from Visual Studio 2005 and show how it uses event handlers to allow the application logic (Crawler class) to communicate with the user interface.&amp;nbsp; The source code for the WebCrawler sample can be downloaded from &lt;A href="http://msdn2.microsoft.com/en-us/library/t7w4afa2.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/t7w4afa2.aspx"&gt;here&lt;/A&gt;.&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Simple Status Notification - EventHandler&lt;BR&gt;&lt;/B&gt;For simple notifications requiring no data, such as the CrawlFinishedEvent in the WebCrawler sample, an event handler is defined in the application logic class.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;public event EventHandler CrawlFinishedEvent;&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;When the application logic wishes to inform clients that the event has occurred, it checks to see if there are any registered event handlers and, if so, sends the notification.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;if (null != CrawlFinishedEvent)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CrawlFinishedEvent(this, EventArgs.Empty);&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;The UI class (MainForm in the WebCrawler) registers for the event.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;this.crawler.CrawlFinishedEvent += new EventHandler(HandleCrawlFinishedEvent);&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;The form implements a method to handle the event.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;/// &amp;lt;summary&amp;gt;&lt;BR&gt;/// Process CrawlFinished events&lt;BR&gt;/// &amp;lt;/summary&amp;gt;&lt;BR&gt;private void HandleCrawlFinishedEvent(object sender, EventArgs e)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update the user interface as appropriate&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Sending Data In The Notification - Creating a Custom EventHandler&lt;BR&gt;&lt;/B&gt;If the notification requires some data data, such as the CurrentPageEvent&amp;nbsp; in the WebCrawler sample, a custom event handler delegate will need to be defined.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;public delegate void CurrentPageEventHandler(object sender, CurrentPageEventArgs e);&lt;BR&gt;public event CurrentPageEventHandler CurrentPageEvent;&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;Notice the CurrentPageEventArgs argument -- this is where the custom data is placed.&amp;nbsp; In the WebCrawler sample, the CurerntPageEventArgs is defined as&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;/// &amp;lt;summary&amp;gt;&lt;BR&gt;/// Class providing the current page address to the CurrentPageEvent handler&lt;BR&gt;/// &amp;lt;/summary&amp;gt;&lt;BR&gt;public class CurrentPageEventArgs : EventArgs&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private string pageAddressValue;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// The address of the current page(ex: &lt;A href="http://www.microsoft.com/" mce_href="http://www.microsoft.com"&gt;http://www.microsoft.com&lt;/A&gt;)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string PageAddress&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get&lt;BR&gt;&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; return this.pageAddressValue;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Constructor&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;param name="page"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// The address of the current page&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/param&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public CurrentPageEventArgs(string page)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.pageAddressValue = page;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;As with the above simple status notification example, when the application logic wishes to inform clients that the event occurred, it checks registrations and sends the notification, passing the data in the event arguments.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;if (CurrentPageEvent != null)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CurrentPageEvent(this,&amp;nbsp; new CurrentPageEventArgs(str));&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;Registering for the custom event is similar to the above simple notification example.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;this.crawler.CurrentPageEvent += new Crawler.CurrentPageEventHandler(HandleCurrentPageEvent);&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;The implementation of the event handler method needs to match the custom event handler delegate.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;/// &amp;lt;summary&amp;gt;&lt;BR&gt;/// Process CurrentPage events&lt;BR&gt;/// &amp;lt;/summary&amp;gt;&lt;BR&gt;private void HandleCurrentPageEvent(object sender, CurrentPageEventArgs e)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update the user interface as appropriate&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;By building and running the WebCrawler sample under the Visual Studio 2005 debugger, you can watch the event notifications and how the sample handles &lt;A href="http://blogs.msdn.com/davidklinems/archive/2005/03/21/400102.aspx" mce_href="http://blogs.msdn.com/davidklinems/archive/2005/03/21/400102.aspx"&gt;updating user interface elements in a multi-threaded application&lt;/A&gt;.&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK&lt;BR&gt;&lt;BR&gt;&lt;FONT size=1&gt;Disclaimer(s):&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;BR&gt;&amp;nbsp;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=794721" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Programmatically Rotating the Screen using the .NET Compact Framework</title><link>http://blogs.msdn.com/davidklinems/archive/2006/04/17/577897.aspx</link><pubDate>Tue, 18 Apr 2006 03:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:577897</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/577897.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=577897</wfw:commentRss><description>Several months back, I wrote about how to &lt;A HREF="/davidklinems/archive/2005/06/16/430000.aspx"&gt;determine whether or not a device supported screen rotation&lt;/A&gt;.&amp;nbsp; This post prompted the question of how to programmatically rotate the device..&lt;BR&gt;&lt;BR&gt;The snippets below check the device's current display orientation.&amp;nbsp; If portrait (Angle0), the orientation is changed to landscape (Angle90).&amp;nbsp; If the device has any orientation other than Angle0, it is changed to portrait.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;&lt;B&gt;C#&lt;/B&gt;&lt;BR&gt;&lt;CODE&gt;//--------------------------------------------------------------------- &lt;BR&gt;//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;//PARTICULAR PURPOSE. &lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;using System;&lt;BR&gt;using Microsoft.WindowsCE.Forms;&lt;BR&gt;&lt;BR&gt;class Program&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; static void Main()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(SystemSettings.ScreenOrientation == ScreenOrientation.Angle0)&lt;BR&gt;&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; // if portrait, change to landscape&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; SystemSettings.ScreenOrientation = ScreenOrientation.Angle90;&lt;BR&gt;&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; else&lt;BR&gt;&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; // change to portrait&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; SystemSettings.ScreenOrientation = ScreenOrientation.Angle0;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;&lt;B&gt;VB&lt;/B&gt;&lt;BR&gt;&lt;CODE&gt;'--------------------------------------------------------------------- &lt;BR&gt;'THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;'KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;'IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;'PARTICULAR PURPOSE. &lt;BR&gt;'---------------------------------------------------------------------&lt;BR&gt;Imports Microsoft.WindowsCE.Forms&lt;BR&gt;Module Module1 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Sub Main()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If (SystemSettings.ScreenOrientation = ScreenOrientation.Angle0) Then &lt;BR&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; ' if portrait, change to landscape&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; SystemSettings.ScreenOrientation = ScreenOrientation.Angle90 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Else &lt;BR&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; ' change to portrait&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; SystemSettings.ScreenOrientation = ScreenOrientation.Angle0 &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; End Sub &lt;BR&gt;&lt;BR&gt;End Module&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;For more information on this and other cool settings provided by the &lt;A href="http://msdn2.microsoft.com/en-us/library/microsoft.windowsce.forms(VS.80).aspx"&gt;Microsoft.WindowsCE.Forms&lt;/A&gt; namespace, check out the MSDN documentation for &lt;A href="http://msdn2.microsoft.com/en-us/library/microsoft.windowsce.forms.systemsettings(VS.80).aspx"&gt;SystemSettings&lt;/A&gt;.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;--DK&lt;BR&gt;&lt;BR&gt;&lt;FONT size=1&gt;Disclaimer(s):&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;BR&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=577897" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Chris Lorton on alpha blending with the .NET Compact Framework</title><link>http://blogs.msdn.com/davidklinems/archive/2006/04/08/571733.aspx</link><pubDate>Sun, 09 Apr 2006 04:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:571733</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/571733.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=571733</wfw:commentRss><description>Ever wonder how to write applications with really cool, alpha blended user interfaces?&amp;nbsp; If so, take a walk over to &lt;A HREF="/chrislorton"&gt;Chris Lorton's weblog&lt;/A&gt;.&amp;nbsp; There, he has &lt;A HREF="/chrislorton/archive/2006/04/07/570649.aspx"&gt;examples&lt;/A&gt; of using the .NET Compact Framework and Windows Mobile 5.0 to do just that.&amp;nbsp; He covers using the AlphaBlend function and the IImage interface.&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK&lt;BR&gt;&lt;BR&gt;&lt;FONT size=1&gt;Disclaimer(s): &lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=571733" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Why do I get a NotSupportedException when updating a TextBox?</title><link>http://blogs.msdn.com/davidklinems/archive/2006/03/09/548235.aspx</link><pubDate>Fri, 10 Mar 2006 09:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:548235</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/548235.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=548235</wfw:commentRss><description>&lt;P&gt;Have you ever been working on an application and found that when the code tries to update the Text property of a TextBox control that you encounter a NotSupportedException?&amp;nbsp; Have you seen this with a Label, ListBox, Button or another control?&amp;nbsp; If you have, the application is attempting to update the control from a worker thread instead of the thread that created the control (typically the main application thread).&amp;nbsp; Today I would like to examine why this happens.&lt;BR&gt;&lt;BR&gt;On version 1 of the .NET Compact Framework, applications which attempted to update their user interface from a worker thread would typically hang.&amp;nbsp; Having an application hang is an unpleasant user experience.&lt;BR&gt;&lt;BR&gt;With the release of version 2, the .NET Compact Framework will throw a NotSupportedException in the scenarios that would have previously lead to an application hang.&amp;nbsp; While exceptions are still not the best experience, they are far better than an application hanging.&amp;nbsp; Since the .NET Compact Framework is specifically throwing in this scenario, the application developer will find the issue every time a control is updated from a worker thread and the developer can fix the code.&lt;BR&gt;&lt;BR&gt;If your device has had the &lt;A href="/netcfteam/archive/2004/08/06/210232.aspx"&gt;string resource assemblies&lt;/A&gt; installed, the Message property of the NotSupportedException will contain an explanation for why the exception was thrown.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;Control.Invoke must be used to interact with controls created on a separate thread.&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Examples&lt;BR&gt;&lt;/B&gt;Let's take a look at a couple of examples of what I have been talking about.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;The first snippet illustrates a simple thread delegate that attempts to update a TextBox control's Text property directly.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;private void TestThread() &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update our status &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.textBox1.Text = "Thread running"; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // run until told to stop &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while(!this.stopNow) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // simulated processing &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.Sleep(1000); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update our status &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.textBox1.Text = "Thread stopped"; &lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;The above example will cause a NotSupportedException to be thrown on the line:&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;this.textBox1.Text = "Thread running";&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Note also that the last line in the method will also cause a NotSupportedException to be thrown.&amp;nbsp; Let's take a look at a fix.&amp;nbsp; &lt;BR&gt;&lt;BR&gt;The first step to fix our snippet is to define a delegate that takes a String argument so that we can pass our status message.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;private delegate void UpdateStatusDelegate(String message);&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Next, we add an implementation of a method that matches our delegate's signature.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;private void DoUpdate(String message)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(this.InvokeRequired)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // we were called on a worker thread&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // marshal the call to the user interface thread&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.Invoke(new UpdateStatusDelegate(DoUpdate), &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; new object[] { message });&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // this code can only be reached&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // by the user interface thread&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.textBox1.Text = message; &lt;BR&gt;} &lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;And, finally, we modify our thread method to call DoUpdate and pass the desired status message.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;private void TestThread()&lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update our status &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoUpdate("Thread running");&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // run until told to stop&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while(!this.stopNow)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // simulated processing&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.Sleep(1000);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // update our status&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; DoUpdate("Thread stopped");&lt;BR&gt;}&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Now, let's take a look at how this works.&amp;nbsp; When the thread method (TestThread) calls DoUpdate, the first thing that happens is that the Form's InvokeRequired method is called.&amp;nbsp; InvokeRequired compares the current thread with the thread which created the Form.&amp;nbsp; Since the threads are different (we called DoUpdate on a worker thread), we enter the if block.&lt;BR&gt;&lt;BR&gt;Next, DoUpdate calls the Form's Invoke method and passes itself as a new instance of our UpdateStatusDelegate with the message argument encapsulated in an Object array.&amp;nbsp; Invoke then calls the DoUpdate method on the thread which created the Form.&amp;nbsp; After the call to Invoke completes, DoUpdates returns.&amp;nbsp; This return step is necessary so that the remainder of the method (the TextBox update) does not get called by the worker thread.&lt;BR&gt;&lt;BR&gt;When DoUpdate is called by Invoke, it again calls the Form's InvokeRequired method.&amp;nbsp; This time, the call was made on the thread which created the Form, we skip the if block and the TextBox is updated.&lt;BR&gt;&lt;BR&gt;Please note that for the above to work on version 1 of the .NET Compact Framework, you will need to write and call your own custom InvokeRequired method. I talk about one implementation for InvokeRequired in &lt;A href="/davidklinems/archive/2005/03/21/400102.aspx"&gt;my post on the Visual Studio .NET 2003 Web Crawler sample&lt;/A&gt;.&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Hidden threads&lt;BR&gt;&lt;/B&gt;Sometimes, and application can be multi-threaded without realizing it.&amp;nbsp; When using the asynchronous programming model, your application's callback methods are called on a worker thread created and managed by the .NET Compact Framework runtime.&amp;nbsp; It is important to keep this in mind when using asynchronous methods and be sure that your user interface is updated only by the UI thread.&lt;BR&gt;&lt;BR&gt;When I'm using an asynchronous callback method, I also write a delegate that I Invoke as appropriate.&amp;nbsp; This ensures that my user interface updates occur in the correct context.&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK&lt;BR&gt;&lt;BR&gt;&lt;FONT size=1&gt;[Edit: update snippet formatting]&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1&gt;Disclaimer(s):&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=548235" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Using a UserControl to combine related controls</title><link>http://blogs.msdn.com/davidklinems/archive/2005/11/23/496552.aspx</link><pubDate>Thu, 24 Nov 2005 06:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:496552</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/496552.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=496552</wfw:commentRss><description>Have you been writing an application where you needed to relate multiple controls to each other (ex: a Button and a TextBox) where multiple sets of the related controls are required?&lt;BR&gt;&lt;BR&gt;&lt;B&gt;The scenario&lt;/B&gt;&lt;BR&gt;I have an application where I needed to have multiple Button controls which I needed to perform the same task.&amp;nbsp; This task was to read the value of a specific TextBox's Text property and call a method using that data.&amp;nbsp; My goals were to minimize redundant code and to not be required to create a new Click event handler whenever I added a TextBox / Button control pair to my form.&lt;BR&gt;&lt;BR&gt;One of the best things about the Button (and other controls) click event is that your event handler is sent the object that generated the event in the sender argument.&amp;nbsp; I originally planned (and wrote) my click event handler such that it identified the sender (Button) and then examined each of its parent's controls to find the matching TextBox control.&amp;nbsp; After some trial and error, which underscored the fragility of my algorithm, I got the code working.&amp;nbsp; The code wasn't pretty, nor did it perform very well.&amp;nbsp; I could live with the code not being super elegant (heavy commenting helped) but I didn't like the performance characteristics (it didn't scale well) and the reliance upon adhering to specific naming conventions was a major issue.&lt;BR&gt;&lt;BR&gt;&lt;B&gt;One solution&lt;/B&gt;&lt;BR&gt;Since I was writing my application using version 2 of the .NET Compact Framework, I decided to re-implement my solution as a UserControl.&amp;nbsp; UserControls are a great way to combine multiple UI controls such that the container (an application's form) can treat them as one unit with a unified public interface.&amp;nbsp; In a UserControl, you can specify how the default control properties (ex: Text) behave and define additional properties that make sense for your control.&lt;BR&gt;&lt;BR&gt;And best of all, they are very easy to write using Visual Studio 2005.&lt;BR&gt;&lt;BR&gt;My main goal in implementing this control was to make the control's click event be synonymous with the child Button's click event.&amp;nbsp; An alternative would be to expose the Button's click event as a new event (ex: ActionButtonClick) that a form could handle -- I have an example of this alternative following this discussion.&lt;BR&gt;&lt;BR&gt;First, I added a new UserControl to my project (you can also create a separate project for your control).&amp;nbsp; Next, I used the designer to add the controls that will make up my UserControl.&amp;nbsp; After setting the properties of each child control (ex: Anchor settings), I was ready to add the code.&amp;nbsp; The example below implements a very simple Button / TextBox pair with a Label.&lt;BR&gt;&lt;BR&gt;Please note that this is not a complete implementation.&amp;nbsp; I have left out the control designer's generated code (ex: InitializeComponent).&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;//--------------------------------------------------------------------- &lt;BR&gt;//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;//PARTICULAR PURPOSE. &lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;using System;&lt;BR&gt;using System.ComponentModel;&lt;BR&gt;using System.Drawing;&lt;BR&gt;using System.Windows.Forms;&lt;BR&gt;&lt;BR&gt;public partial class LinkedButtonAndTextBox : UserControl&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// This variable helps to ensure that the button's click&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// is the only click we forward to the form&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private Boolean myButtonWasClicked;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; The value of the Text property of the child Label control&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public String Label&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get{ return this.label.Text; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set{ this.label.Text = value; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; The value of the Text property of the child TextBox control&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override String Text&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get{ return this.textBox.Text; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set{ this.textBox.Text = value; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; The value of the Text property of the child Button control&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override String ButtonText&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get{ return this.button.Text; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; set{ this.button.Text = value; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; Control constructor&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public LinkedButtonAndTextBox()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // by default, the button has not been clicked&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.myButtonWasClicked = false;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // designer generated method to&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; create and add child controls and to set&lt;BR&gt;&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; InitializeComponent();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Event handler called when our button is clicked.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; This event handler method was registered using the Visual Studio control designer.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;param name="sender"&amp;gt;The object on which the click occurred&amp;lt;/param&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;param name="e"&amp;gt;EventArgs describing the event&amp;lt;/param&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private void button_Click(Object sender, EventArgs e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // indicate that the click event originated from our button's&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //&amp;nbsp; click handler&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.myButtonWasClicked = true;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // click the control (call LinkedButtonAndTextBox.OnClick)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.OnClick(e);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Raise the click event &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void OnClick(EventArgs e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // did the click originate from our button control?&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(this.myButtonWasClicked)&lt;BR&gt;&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; // yes&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; &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; // reset the button clicked flag&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; this.myButtonWasClicked = false;&lt;BR&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; // call the our base class's OnClick method (UserControl.OnClick)&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; base.OnClick(e);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;&lt;B&gt;How it works&lt;/B&gt;&lt;BR&gt;The key to this solution is the use of the myButtonWasClicked member variable.&amp;nbsp; By setting the value to true in the button_Click method before calling OnClick, the control knows to call any registered click handlers (by calling the base classes implementation of OnClick).&amp;nbsp; If the value is false, the click event is not forwarded to the registered click handlers.&lt;BR&gt;&lt;BR&gt;Applications can register interest in your click event by adding a delegate to the event handler chain:&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;LinkedButtonAndTextBox btnTextBox1 = new LinkedButtonAndTextBox():&lt;BR&gt;btnTextBox1.Click += btnTextBox_Click:&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Visual Studio 2005 will add code similar to the above lines when you add the control to a form and double-click on it for the first time.&amp;nbsp; An event handler method will also be generated on your behalf.&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Another solution&lt;/B&gt;&lt;BR&gt;Earlier I mentioned that an alternative solution would be to not override the control's OnClick method and, instead, to add a specific click event for the button.&amp;nbsp; We'll call this new event ActionButtonClick.&amp;nbsp; Rather than reiterate a good deal of the above example, I am going to show just an implementation for the ActionButtonClick event.&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;//--------------------------------------------------------------------- &lt;BR&gt;//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;//PARTICULAR PURPOSE. &lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;using System;&lt;BR&gt;using System.ComponentModel;&lt;BR&gt;using System.Drawing;&lt;BR&gt;using System.Windows.Forms;&lt;BR&gt;&lt;BR&gt;public partial class LinkedButtonAndTextBox : UserControl&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; //*** code omitted for size and clarity ***&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// The event handler that forms can register to&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// receive notification that our button has been&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// clicked.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public event EventHandler ActionButtonClick;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Event handler called when our button is clicked&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ///&amp;nbsp; This event handler method was registered using the Visual Studio control designer.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;param name="sender"&amp;gt;The object on which the click occurred&amp;lt;/param&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;param name="e"&amp;gt;EventArgs describing the event&amp;lt;/param&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected override void button_Click(Object sender, EventArgs e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // raise the event&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.OnActionButtonClick(e);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Raise the ActionButtonClick event&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected virtual void OnActionButtonClick(EventArgs e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // check to see if an event handler has been registered&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(this.ActionButtonClick != null)&lt;BR&gt;&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; // call the registered event handler(s)&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; this.ActionButtonClick(this, e);&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; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;The above example allows an application to register to be notified whenever the LinkedButtonAndTextBox's button control has been clicked while still allowing notification of clicks occurring on other areas of the control.&amp;nbsp; Depending on the control you write, this approach may be the one you are looking for.&lt;BR&gt;&lt;BR&gt;It is important to check the event handler's (ActionButtonClick) value against null before making the call to avoid possible NullReferenceExceptions.&lt;BR&gt;&lt;BR&gt;Which solution you choose to use will depend on the intent of your control.&amp;nbsp; For my current application, the first solution made more sense to me.&amp;nbsp; I would not be surprised if my next application were to use the second approach. :)&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1&gt;[Edit: minor tweak]&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=1&gt;Disclaimer(s): &lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=496552" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Adding a Non-Modal Splash Screen to your .NET Compact Framework Application</title><link>http://blogs.msdn.com/davidklinems/archive/2005/08/17/452804.aspx</link><pubDate>Wed, 17 Aug 2005 23:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:452804</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/452804.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=452804</wfw:commentRss><description>A few weeks ago, &lt;a href="http://blogs.msdn.com/anthonywong/"&gt;Anthony Wong&lt;/A&gt; posted an excellent entry on &lt;a href="http://blogs.msdn.com/anthonywong/archive/2005/07/28/444684.aspx"&gt;adding a modal splash screen to your .NET Compact Framework application&lt;/A&gt;.  His post started me wondering about how to create a non-modal splash screen.  Why a non-modal splash screen?  By making the splash screen non-modal, the application's main form can perform initialization work while the splash form is displayed.  Once initialization is complete, the main form will close the splash screen form.&lt;BR&gt;&lt;BR&gt;The snippets below display the relevant code for a single-threaded application that displays a non-modal splash screen, performs initialization and closes the splash screen when finished.  Please note that this example uses version 2 of the .NET Compact Framework.&lt;BR&gt;&lt;BR&gt;&lt;U&gt;&lt;B&gt;Main application form&lt;BR&gt;&lt;/B&gt;&lt;/U&gt;&lt;CODE&gt;&lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;//PARTICULAR PURPOSE.&lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;namespace NonModalSplashSnippet&lt;BR&gt;{&lt;BR&gt;    public partial class MainForm() : Form&lt;BR&gt;    {&lt;BR&gt;        private SplashForm m_Splash;&lt;BR&gt;&lt;BR&gt;        public MainForm()&lt;BR&gt;        {&lt;BR&gt;            // create and display the splash screen form&lt;BR&gt;            //  and make the main form it's owner&lt;BR&gt;            this.m_Splash = new SplashForm();&lt;BR&gt;            this.m_Splash.Owner = this;&lt;BR&gt;            this.m_Splash.Show();&lt;BR&gt;&lt;BR&gt;            // process the message queue&lt;BR&gt;            //  this is done to allow the splash&lt;BR&gt;            //  screen to be painted&lt;BR&gt;            Application.DoEvents();&lt;BR&gt;&lt;BR&gt;            // disable the main form&lt;BR&gt;            //  to avoid the title bar&lt;BR&gt;            //  being drawn over the splash screen&lt;BR&gt;            //  during initialization&lt;BR&gt;            this.Enabled = false;&lt;BR&gt;&lt;BR&gt;            InitializeComponent();&lt;BR&gt;        }&lt;BR&gt;&lt;BR&gt;        private void MainForm_Load(object sender, EventArgs e)&lt;BR&gt;        {&lt;BR&gt;            // do form load-time work&lt;BR&gt;            //  this sleep simulates the work&lt;BR&gt;            System.Threading.Thread.Sleep(10000);&lt;BR&gt;&lt;BR&gt;            // re-enable the form and&lt;BR&gt;            //  tell Windows Forms to &lt;BR&gt;            //  make our form visible&lt;BR&gt;            //  right now&lt;BR&gt;            this.Enabled = true;&lt;BR&gt;            this.Visible = true;&lt;BR&gt;&lt;BR&gt;            // close the splash screen&lt;BR&gt;            this.m_Splash.Close(); &lt;BR&gt;        }&lt;BR&gt;    }&lt;BR&gt;}&lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;&lt;U&gt;&lt;B&gt;Splash screen form&lt;/B&gt;&lt;/U&gt;&lt;BR&gt;&lt;BR&gt;&lt;CODE&gt;//---------------------------------------------------------------------&lt;BR&gt;//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY &lt;BR&gt;//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE &lt;BR&gt;//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A &lt;BR&gt;//PARTICULAR PURPOSE.&lt;BR&gt;//---------------------------------------------------------------------&lt;BR&gt;namespace NonModalSplashSnippet&lt;BR&gt;{&lt;BR&gt;    public partial class SplashForm() : Form&lt;BR&gt;    {&lt;BR&gt;&lt;BR&gt;        public SplashForm()&lt;BR&gt;        {&lt;BR&gt;            // use the form designer to set&lt;BR&gt;            //  ControlBox == false&lt;BR&gt;            //  WindowState == Maximized&lt;BR&gt;            // This results in a full screen splash&lt;BR&gt;            //  form without a title bar&lt;BR&gt;            InitializeComponent();&lt;BR&gt;        }&lt;BR&gt;&lt;BR&gt;        protected override OnPaint(PaintEventArgs e)&lt;BR&gt;        {&lt;BR&gt;&lt;BR&gt;            // display a message&lt;BR&gt;            StringFormat sf = new StringFormat();&lt;BR&gt;            sf.Alignment = StringAlignment.Center;&lt;BR&gt;            sf.LineAlignment = StringAlignment.Center; &lt;BR&gt;            e.Graphics.DrawString(".NET Compact Framework", &lt;BR&gt;                                  this.Font, &lt;BR&gt;                                  new SolidBrush(Color.Blue), &lt;BR&gt;                                  Screen.PrimaryScreen.Bounds, &lt;BR&gt;                                  sf);&lt;BR&gt;        }&lt;BR&gt;    }&lt;BR&gt;}&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;&lt;U&gt;&lt;B&gt;How it works&lt;BR&gt;&lt;/B&gt;&lt;/U&gt;Let's walk through the snippets and discuss what is happening.&lt;BR&gt;&lt;BR&gt;The first job our application's main form performs is the creation of the splash screen form.  Once created, the splash screen's owner is set to the instance of the MainForm class and then it is shown.&lt;BR&gt;&lt;CODE&gt;    this.m_Splash = new SplashForm();&lt;BR&gt;    this.m_Splash.Owner = this;&lt;BR&gt;    this.m_Splash.Show();&lt;BR&gt;&lt;/CODE&gt;The setting of the splash form's owner is an important step that instructs the operating system, provided your application is the currently active application, to display the application's main form once the splash form is closed.&lt;BR&gt;&lt;BR&gt;To ensure that the splash screen form gets painted (and all other pending messages get processed) the static Application.DoEvents method is called.&lt;BR&gt;&lt;CODE&gt;    Application.DoEvents();&lt;/CODE&gt;&lt;BR&gt;&lt;BR&gt;To avoid the main form's caption being displayed on top of the splash screen, the MainForm constructor sets the form's enabled property to false and then calls InitializeComponent (created by the Visual Studio 2005 form designer).&lt;BR&gt;&lt;CODE&gt;    this.Enabled = false;&lt;BR&gt;&lt;/CODE&gt;Since the default value for the Enabled property is true, the designer does not explicitly set the value, which leaves our setting of false preserved.&lt;BR&gt;&lt;BR&gt;The MainForm_Load method is where initialization will occur.  In my snippet, I sleep for a few seconds to simulate work being performed.  Once the initialization is complete, the main form is re-enabled and marked visible.&lt;BR&gt;&lt;CODE&gt;    this.Enabled = true;&lt;BR&gt;    this.Visible = true;&lt;BR&gt;&lt;/CODE&gt;By explicitly marking the main form visible, the system is being told that it is now time to display the form.&lt;BR&gt;&lt;BR&gt;The last thing done in MainForm_Load is to close the splash screen.&lt;BR&gt;&lt;CODE&gt;    this.m_Splash.Close(); &lt;BR&gt;&lt;/CODE&gt;&lt;BR&gt;Once the splash screen is closed, the main form is displayed and is ready to be used.&lt;BR&gt;&lt;BR&gt;Enjoy!&lt;BR&gt;-- DK&lt;BR&gt;&lt;BR&gt;&lt;FONT size=1&gt;[Edit: update links]&lt;BR&gt;[Edit: fix error]&lt;BR&gt;&lt;BR&gt;Disclaimer(s):&lt;BR&gt;This posting is provided "AS IS" with no warranties, and confers no rights. &lt;BR&gt;Some of the information contained within this post may be in relation to beta software. Any and all details are subject to change.&lt;/FONT&gt; 
&lt;P&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=452804" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Tips+and+Tricks/default.aspx">Tips and Tricks</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item><item><title>Exploring the NetCF Web Crawler sample (Visual Studio .NET 2003) - Part II: Updating the UI</title><link>http://blogs.msdn.com/davidklinems/archive/2005/03/21/400102.aspx</link><pubDate>Mon, 21 Mar 2005 23:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:400102</guid><dc:creator>DavidKlineMS</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/davidklinems/comments/400102.aspx</comments><wfw:commentRss>http://blogs.msdn.com/davidklinems/commentrss.aspx?PostID=400102</wfw:commentRss><description>&lt;p&gt;A couple of weeks ago, I discussed &lt;A href="http://blogs.msdn.com/davidklinems/archive/2005/03/08/389698.aspx"&gt;link tracking in the NetCF Web Crawler sample&lt;/a&gt; from Visual Studio .NET 2003.&amp;nbsp; Today, I would like to use the Web Crawler sample to discuss updating an application's user interface from a worker thread.&lt;/p&gt; &lt;p&gt;When updating user interface elements, it is very important to perform the tasks while running in the context of the thread that created the controls.&amp;nbsp; One side effect of attempting to modify controls from a different thread are application hangs.&amp;nbsp; This is most often seen when attempting to update a control (ex: modify it's Text property) in a asynchronous method callback.&amp;nbsp; While callback methods typically live in the class that owns the controls, they are most often called by a thread that was created by another piece of code (the NetCF HTTP client class library, for example).&amp;nbsp; When UI updates are attempted from this callback, application hangs may occur.&lt;/p&gt; &lt;p&gt;The way to avoid these side effects is to marshal the callback calls to your user interface's thread context.&amp;nbsp; This can be achived using the Invoke method of the System.Windows.Forms.Control class.&amp;nbsp; The Web Crawler example uses this technique to provide runtime status to the user.&lt;/p&gt; &lt;p&gt;NOTE: The code in this post has been edited for clarity and to reduce size.&amp;nbsp; For full sample code, please consult the files that were installed with Visual Studio .NET 2003 (\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Samples\VC#\Pocket PC\WebCrawler).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Events and event handlers&lt;br /&gt;&lt;/strong&gt;The Web Crawler's Crawler class supports a number of events for which that clients can register handlers.&amp;nbsp; To keep my example as clear as possible, I am going to focus on a very simple case -- the PageFoundEvent.&amp;nbsp; &lt;/p&gt; &lt;p&gt;The WebCrawler.Crawler object exposes a public EventHandler field for the PageHandledEvent as shown below:&lt;/p&gt;&lt;code&gt; &lt;p&gt;public EventHandler PageFoundEvent;&lt;/p&gt;&lt;/code&gt; &lt;p&gt;The client (WebCrawler.MainForm) registers it's event hander:&lt;/p&gt;&lt;code&gt; &lt;p&gt;// from startButton_Click&lt;br /&gt;this.crawler = new Crawler(startingPage,&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; noProxy);&lt;br /&gt;this.crawler.PageFoundEvent += new EventHandler(this.HandlePageFoundEvent);&lt;/p&gt;&lt;/code&gt; &lt;p&gt;The event handler implementation also lives in the client (WebCrawler.MainForm):&lt;/p&gt;&lt;code&gt; &lt;p&gt;private void HandlePageFoundEvent(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(CustomInvokeRequired())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.linkCount.Invoke(new EventHandler(this.HandlePageFoundEvent));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;br /&gt;&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; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.linkCount.Text = string.Format("{0}", Int32.Parse(this.linkCount.Text)+1);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch(FormatException)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { }&lt;br /&gt;}&lt;/p&gt;&lt;/code&gt; &lt;p&gt;The HandlePageFoundEvent method first checks to see if the call was made in the context of the user interface thread by calling CustomInvokeRequired() (more on this soon).&amp;nbsp; If not (returns true), it calls the linkCount object's Invoke method to marshal the call to the user interface thread.&amp;nbsp; The HandlePageFoundEvent method is then re-called on the user interface thread.&amp;nbsp; CustomInvokeRequired() is called (returns false) and the method updates the linkCount control's Text property.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Determining if thread marshaling is required&lt;br /&gt;&lt;/strong&gt;I mentioned earlier that I would go into more detail on the web crawler's CustomInvokeRequired method (WebCrawler.MainForm).&amp;nbsp; At startup, the web crawler's MainForm object stores it's thread in a private member variable:&lt;/p&gt;&lt;code&gt; &lt;p&gt;private readonly System.Threading.Thread FormThread = System.Threading.Thread.CurrentThread;&lt;/p&gt;&lt;/code&gt; &lt;p&gt;This member is marked as readonly so that it cannot be modified.&lt;/p&gt; &lt;p&gt;When called, the CustomInvokeRequired method checks to see if the current thread is the same as the FormThread (the thread that owns the user interface):&lt;/p&gt;&lt;code&gt; &lt;p&gt;if(this.FormThread.Equals(System.Threading.Thread.CurrentThread))&lt;/p&gt;&lt;/code&gt; &lt;p&gt;If the current thread is the user interface thread (&lt;code&gt;this.FormThread.Equals(Thread.CurrentThread)&lt;/code&gt;), there is no marshaling required and CustomInvokeRequired returns false.&amp;nbsp; Otherwise, true is returned indicating that thread marshaling is needed.&lt;/p&gt; &lt;p&gt;Using this technique, the web crawler's worker thread can keep the user informed, and not cause any undesirable side effects.&lt;/p&gt; &lt;p&gt;Until next time,&lt;br /&gt;-- DK&lt;/p&gt; &lt;p&gt;&lt;font size="1"&gt;Disclaimer(s):&lt;br /&gt;This posting is provided "AS IS" with no warranties, and confers no rights.&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=400102" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/davidklinems/archive/tags/Networking+_26002600_+Web+Services/default.aspx">Networking &amp;&amp; Web Services</category><category domain="http://blogs.msdn.com/davidklinems/archive/tags/GUI/default.aspx">GUI</category></item></channel></rss>