<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Michal-Altair-Valek/Posts/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9</title>
      <link>http://channel9.msdn.com/Niners/c4f.Michal-Altair-Valek/Posts</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Niners/c4f.Michal-Altair-Valek/Posts</link>
    <language>en</language>
    <pubDate>Thu, 20 Jun 2013 05:00:07 GMT</pubDate>
    <lastBuildDate>Thu, 20 Jun 2013 05:00:07 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>1</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Hidden Image Game</title>
      <description><![CDATA[ <p>In this article, we'll create a Hidden Image game. We'll demostrate few features available in Windows Forms in Microsoft .NET 2.0 for creating a consistent and user-friendly interface.</p><p>Recently I was challenged to quickly write an application for playing the Hidden Image game, popularized here in the Czech Republic by a certain TV show. Luckily I had my notebook with Visual Basic Express at hand. This example shows how easy it is to write software in Visual Basic Express, and how to almost effortlessly create a well-behaved Windows application. It also demonstrates how to use certain new features available in Windows Forms in Microsoft .NET 2.0 for creating a consistent and user-friendly interface using the following techniques: </p><ul><li>GUI design basics with Windows Forms Designer. </li><li>Storing configuration settings for an application. </li><li>Creating a borderless, full-screen window and dynamically generating controls in it. </li></ul><h4>Rules of the Game</h4><p>Hidden Image is not a computer game in the pure sense — it's more like a puzzle. Here's where a computer comes in handy, because it's simpler to show an image on the wall using a video projector than with cut paper cards (especially for us computer geeks, of course).) </p><p>To play the Hidden Image game, you need two opposite sides (players or teams) and one game master. The game master chooses an image. When displayed, the image is covered by numbered squares. Each player takes a turn removing one square, which reveals a portion of the image, and then attempts to guess what the image is. If the guess is correct, the player wins the game. If it's an incorrect guess, the other side takes a turn. </p><p>For this application I wanted to allow the game master to select the picture, set up certain parameters (like the number and color of the squares), and then display the covered picture. When clicking on any square, the square would disappear and reveal a part of the picture underneath. Pressing the ENTER key would reveal the entire picture, and pressing the ESC key would return you to the setup screen. </p><h4>The Best User Experience</h4><p>Certain applications are very visually appealing. They have fantastic colors, fantastic forms shapes, and rich graphics. They are beautiful. Unfortunately, in most cases they're not very useful. Unless your application is a role-playing adventure game, it is not a good idea to let your user wonder if the gimmick on the screen is actually a button or only a figment of the designer's imagination. </p><p>One key reason for the success of the Windows operating system is that the elements are generally the same in all the applications. You'll quickly realize that this is a menu, this is a button, and that this little square is actually a check box. Your applications should likewise follow common rules rather than trying to reinvent the wheel. </p><p>An application should also behave well on differing system configurations and not just on the machine that created it. Certain users — for example, me — have the taskbar on top of the screen instead of at the bottom. Some users like very high resolutions (for example, 1600 x 1200), while others prefer lower (and easier to read) resolutions (for example, 1024 x 768). Therefore it is a good idea to plan on making your Windows Forms resizable for the user's viewing comfort. And when the user resizes or moves Window Forms, the application should remember these changes and place the form in the same position the next time the user runs the application. It is also good to keep in mind that the computer may have different user accounts, and that user changes and preferences need to be stored per user. </p><p>This is the art of designing a decent user interface that creates the best user experience. Users, even inexperienced ones, should be able to use your application without unnecessary confusion. </p><p>Sound tricky? Not really. Microsoft .NET 2.0 has lots of features that allow you to painlessly address all these issues. You just need to know about them. </p><h4>Creating the User Interface</h4><p>Let's start Visual Basic Express and create a new Windows Application project (or simply download and open the finished project attached to this article). After creating the application, you'll see an empty form ready for you to place controls on it. </p><p>Below is what the finished application setup form should look like: </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage001.gif" alt=""></p><h4>Placing Controls on the Form</h4><p>Begin with placing the group boxes, buttons, and text boxes. You'll notice that if you place a control near to another control or form border, little blue lines appear from the control sides. These lines help you to place the controls the same distance from one another and from the form boundaries. This new feature in Visual Studio 2005 makes aligning controls very easy. </p><p>When designing forms, you can also display the Layout toolbar. Right-click any toolbar and, in the resulting pop-up menu, click &quot;Layout.&quot; A new toolbar will appear, with buttons to align the controls in relation to one another, make similar controls the same size, center them, and so on. Just play with the buttons and discover what they do. </p><p>At this time, there are a few regular controls on the form: </p><ul><li>Two <strong>GroupBox</strong> controls, to group settings for a background picture and for overlay buttons. </li><li>A <strong>Text box</strong> control for setting a path to the image file. </li><li>A <strong>Button</strong> control to browse for the file. </li></ul><p>For entering the number of rows and columns, you could use text boxes as well #151;. but it's not the best possible solution. You need to be sure that the entered value is a whole number within a certain range, for example between 2 and 20. So it's a good idea to use the <strong>NumericUpDown </strong>control instead of a text box. In the control's Properties window you can specify minimum and maximum values. </p><p>For setting the background and the foreground colors for the displayed number on the overlay squares, you can use two standard <strong>Label</strong> controls with the same border and size properties as those for the text box above them. What matters is their <strong>BackgroundColor</strong> property. Also, near each of them is a button that allows a user to choose the color. </p><p>You can use a similar approach to make it possible for the user to select the font used for the numbers on the overlay squares. Font specification is complicated. For example, you'll need to store font name, size, and style (bold, italic). We'll sort this out later as well, but for now, just place the controls and set their visual values. </p><p>Let's go ahead and run the application. It should display a nice window. You can click the buttons, write text in text boxes, and so on. Nothing will actually happen, but you can play. </p><h4>Resizing the Form</h4><p>Now try to resize window. The window resizes successfully, but the controls do not: If you make the form larger, the controls will remain in the upper-left corner; if you make the form smaller, they will be hidden. You want the controls to resize nicely with the form. </p><p>Close the application and display the properties for any control on the form. Notice the <strong>Anchor</strong><code> </code>property. When you click it, you can select any combination of Top, Bottom, Left, and Right values. </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage002.gif" alt=""></p><p>These values specify how the control should behave when its container control — in this case the <strong>Form</strong> — resizes. By default, <strong>Anchor</strong> is set to Top and Left. This means that the control will retain its distance from the top and left borders of the Window Form. For example, it would be better if the &quot;Start&quot; and &quot;Close&quot; buttons remained at the left and bottom<strong> </strong>borders of the form. Select more than two anchors (for example, Top, Left and Right), and the magic continues: When you resize the form, the control will stick to each selected <strong>Anchor </strong>and will resize as well. Play with the <strong>Anchor </strong>property for all the controls. Some controls (such as buttons) move to adjust to the change in size of the container control, while others (such as group boxes) will actually resize proportionate to the change in size of the container. </p><p>However, despite these built-in resizing features in Windows Forms and controls, it is usually a good idea to place some limits on the user's freedom to resize the form. If the form size becomes too small, some controls will disappear. To prevent this from happening, a Windows Form has <strong>MinimumSize</strong> and<strong> MaximumSize</strong> properties. In the form designer window, try resizing the form to the smallest possible size where all the controls are still fully displayed, readable, and usable. Then in the Properties window, copy the value in the form's <strong>Size </strong>property into the <strong>MinimumSize</strong> field. Now, when you run the application and resize the window, the controls resize nicely without allowing the window to become too small to be useful. </p><h4>Using Common Dialogs</h4><p>Now it's time to write some code and make the application actually do something. First, let's make some of the buttons go live. The &quot;Browse&quot; and &quot;Change&quot; buttons should use Windows common dialog boxes for file browsing and the selection of colors and fonts. There are two reasons for this. First, it's what users expect. Virtually all professionally written Windows programs use this approach, and anything else would seem strange. Second, it's actually the simplest way. Every other solution is harder to implement. It's one of those times when being lazy actually helps. </p><p>Let's start with file selection. Grab the <strong>OpenFileDialog</strong> control (in the Dialogs section of Toolbox) and place it somewhere on the form. It will immediately disappear from wherever you placed it and display in the grey area at the bottom part of the edit pane. This happens because the dialog control does not have any visual implementation on the form itself. It's not like a button or a text box, which are directly visible to users. </p><p>In the Properties window for this control, there are settings for a lot of things, like the title of the dialog, conditions the file must meet (for example, <strong>CheckFileExists</strong>), and so on. For our purposes, there is an interesting property called <strong>Filter</strong>. Values in this property specify what displays in the <strong>Files of type</strong> box. </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage003.gif" alt=""></p><p>For the Hidden Image application, the values would be <code>Images|*.jpg;*.bmp;*.gif;*.png;*.tif;*.tiff|All files|*.*</code>. By default, we would allow users to choose from certain types of image files. As a last resort, a user can view all the files, regardless of extension. The file type extensions are separated by a pipe character. </p><p>Now, let's write a few lines of code that will display the Open File common dialog (pointing to the currently selected file), so that if the user clicks &quot;Open,&quot; the name of the currently selected file appears in the text box. Double-click the &quot;Browse&quot; button to open the code editing pane and write the following code as handler of the <strong>Click </strong>event:</p><p><strong>C#</strong><br><pre class="brush: csharp">private void ButtonBrowse_Click(System.Object sender, System.EventArgs e)
{
    //  Display file browser dialog
    this.OpenFileDialogImage.FileName = this.TextBoxImageFilePath.Text;
    if (this.OpenFileDialogImage.ShowDialog(this) != 
        System.Windows.Forms.DialogResult.OK)
    {
        return;
    }

    this.TextBoxImageFilePath.Text = this.OpenFileDialogImage.FileName;
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub ButtonBrowse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)_
                                Handles ButtonBrowse.Click
    ' Display file browser dialog
    Me.OpenFileDialogImage.FileName = Me.Text boxImageFilePath.Text
    If Me.OpenFileDialogImage.ShowDialog(Me) &lt;&gt; Windows.Forms.DialogResult.OK Then Return
    Me.Text boxImageFilePath.Text = Me.OpenFileDialogImage.FileName
End Sub
</pre></p><p>The approach for the Color common dialog box and color selection is very similar. The code for the Font common dialog box will be a little different so we'll come back to it later. </p><h4>AutoComplete Magic</h4><p>One of the nice features in Windows is auto-completion of text box entries. That's when a user starts to type an entry (for example, a path to a file) and the text box offers possible entries based on previously entered values. To enable this feature in the Hidden Image application, you need to enable a couple of properties for the file name text box on the setup form. Set the <strong>AutoCompleteMode</strong> property to <strong>SuggestAppend </strong>and the <strong>AutoCompleteSource</strong> property to <strong>FileSystem</strong>. </p><h4>Don't Forget the Keyboard</h4><p>Don't forget that people can control your application using the keyboard as well as the mouse. If an application is well designed, advanced users usually find using the keyboard quicker and easier. </p><p>Three things help to make using the keyboard easier and more productive: </p><ul><li>Default buttons. </li><li>Tab order. </li><li>Keyboard accelerators. </li></ul><p>Let's look at default buttons first. In the case of most dialogs, there are buttons like &quot;OK&quot; and &quot;Cancel&quot; that function like the ENTER and ESC keys. You can enable this function using the dialog form's <strong>AcceptButton</strong> and <strong>CancelButton</strong> properties. In this case, set them to the &quot;Start&quot; and &quot;Close&quot; buttons. When you press ENTER or ESC, the application will behave as if the corresponding button has been clicked. The functionality of the &quot;Start&quot; button can be added later, but the &quot;Close&quot; button is easy to enable right away — just close the form: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void ButtonClose_Click(System.Object sender, System.EventArgs e)
{
      //  Close window and quit application
      this.Close();
}

</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub ButtonClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)_
                                Handles ButtonClose.Click
    ' Close window and quit application
    Me.Close()
End Sub
</pre></p><p>Next is the tab order. In a standard application, pressing the TAB key would move the focus to the next control in sequence. The order in which the controls are selected is specified by their <strong>TabIndex </strong>property. For the best user experience, this should follow the order in which the fields are usually filled in, which is usually the same as the order in which the controls line up on the form. </p><p>By default, the tab order is assigned as the controls are placed on the form. The first control is 0, the next control is 1, and so on. In most cases, that's not what we want. Of course you can set the <strong>TabIndex</strong> values by hand, but Visual Basic offers a clever alternative. On the menu, click &quot;View&quot; and then &quot;Tab Order.&quot; You'll notice there are now small squares with numbers in the corners of all the controls: </p><p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage004.gif"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage004_thumb.gif" border="0" alt="Click here for larger image"></a></p><p><strong>(Click image to zoom)</strong> </p><p>Click the controls in the same order you want the tab order to follow. After you're finished, click &quot;View&quot; and then &quot;Tab Order&quot; again to hide the numbers. </p><p>You'll need to assign <strong>TabIndex</strong> values even to controls that are not directly selectable, such as <strong>Labels</strong>. Why? Because of the keyboard accelerators. </p><p>You may notice that some letters on the running form are underlined (you may need to press and hold the ALT key to see this, depending on your system configuration). If you press ALT and the underlined letter, you'll shift the focus to the appropriate control. Or, if the control itself (for example, a label) cannot be selected, the focus moves to the next control in the tab order. So, if you press ALT&#43;I, the text box for entering the file name is selected. </p><p>You can choose which letter is underlined by placing an ampersand before it. If you name the label &quot;&amp;Image File,&quot; the letter &quot;I&quot; will be underlined and used as a keyboard accelerator. This applies to the first letter of most labels. If the letter has already been assigned to another label, the next letter is underlined. So we have &quot;F&amp;ont&quot; here, because &quot;F&quot; is already used in &quot;&amp;Foreground color.&quot; </p><h4>Managing the Application Settings</h4><p>Since the dawn of personal computing, there has been a need to store configuration settings. You can store the settings in many ways: as text files, in the registry, and so on. Microsoft .NET uses XML files for this. And, best of all, you do not need to worry about reading and converting values; it will be done for you automatically. </p><p>Some settings should be stored for all users of the application. This is called &quot;having Application scope.&quot; These settings are usually configured during installation or initial setup by an administrator and should not be modified by regular users. They're stored in an application configuration file that is present in the same directory as the application's EXE file; it has the same name with a &quot;.config&quot; extension added. In this case, there are no such settings. </p><p>All our settings are &quot;per user.&quot; This means that you need to store them someplace the user can read and write (remember, your user must not have administrator privileges). The ideal location for this is the user profile, usually in <strong>C:\Documents and Settings\&lt;User Name&gt;\Local Settings\Application Data\&lt;Vendor Name&gt;\&lt;Product Name&gt;</strong>. Actually, .NET is kind enough to take care of creating and managing the file. You just need to give it some information about your application. </p><p>Go to the Solution Explorer window and double-click &quot;My Project.&quot; A new window will appear. On the Application tab, click the &quot;Assembly Information&quot; button and fill in the information about yourself and the application: </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage005.gif" alt=""></p><p>The values you enter here will be used for specifying the location of the configuration files (among other things). </p><p>While you're in &quot;My Project&quot;, go to the &quot;Settings&quot; tab. Here you can define the configuration properties of your application. Choose a settings name (for example <strong>ImageFilePath</strong>), type (<strong>String</strong>), scope (<strong>User</strong>), and default value (<strong>C:\WINDOWS\Web\Wallpaper\Bliss.bmp</strong>). Note that you can use pretty complex types for your settings, such as color (<strong>System.Drawing.Color</strong>) or font specification (<strong>System.Drawing.Font</strong>). </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage006_thumb.gif" border="0" alt="Click here for larger image"></p><p><strong>(Click image to zoom)</strong> </p><p>Visual Basic will automatically create a proxy class that takes care of reading and writing those values and you'll be able to use them directly with the correct type, for example as <strong>My.Settings.OverlayFont</strong>. </p><p>As you see, this is another example of laziness being a good thing (I just love being a programmer!). Not only are you able to read and write application settings without having to bother about configuration files, but the files are also placed correctly. Your application won't crash if a user does not have write privileges for the file (the user can always save to his profile). Tools like Windows XP File and Settings Transfer Wizard are an added bonus. </p><h4>Using the Application Settings</h4><p>Now it's time to use — read and write — the settings. Basically there are two possible ways to do this. One is to work with them programmatically, using the auto generated <strong>My.Settings</strong> class mentioned before. We can then write the code that will make the button that selects font family, size, etc. go &quot;live.&quot; </p><p>As before, place the <strong>FontDialog </strong>control on the form and write the following code to the <strong>Click </strong>event handler of the appropriate button: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void ButtonFont_Click(System.Object sender, System.EventArgs e)
{
    //  Display font dialog
    this.FontDialogChange.Font = 
        HiddenImage.Properties.Settings.Default.OverlayFont;
    if (this.FontDialogChange.ShowDialog(this) != 
        System.Windows.Forms.DialogResult.OK)
    {
        return;
    }

    HiddenImage.Properties.Settings.Default.OverlayFont = 
        this.FontDialogChange.Font;
    this.LabelFont.Text =
        string.Format(
            &quot;{0}, {1} pt&quot;,
            HiddenImage.Properties.Settings.Default.OverlayFont.Name,
            HiddenImage.Properties.Settings.Default.OverlayFont.SizeInPoints);
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub ButtonFont_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)_
                                    Handles ButtonFont.Click
    ' Display font dialog
    Me.FontDialogChange.Font = My.Settings.OverlayFont
    If Me.FontDialogChange.ShowDialog(Me) &lt;&gt; Windows.Forms.DialogResult.OK Then Return
    My.Settings.OverlayFont = Me.FontDialogChange.Font
    Me.LabelFont.Text = String.Format(&quot;{0}, {1} pt&quot;, My.Settings.OverlayFont.Name, _
        My.Settings.OverlayFont.SizeInPoints)
End Sub
</pre></p><p>The second way to use application settings is declaratively, with property bindings. We'll show an example of this with the image file name text box. Click the text box and display its properties. Find the <strong>(ApplicationSettings)</strong> item in the property box and click the small &quot;<strong>&#43;</strong>&quot; before it. Then click the &quot;<strong>…</strong>&quot; button in the <strong>(PropertyBinding)</strong> row. The following dialog box will appear: </p><p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/909778/c4f-hiddenimage007.gif" alt=""></p><p>You can see that you can bind certain properties to application settings. Actually you can easily create new application settings with correct data types from here (using the &quot;New…&quot; link). </p><p>So, bind the <strong>Text</strong> property to the <strong>ImageFilePath </strong>application setting. In the same way bind all the other controls — for the number of rows and columns, and using <strong>BackgroundColor</strong> for the color specification labels. </p><p>Not everything can be bound in this way. For example, you would not use binding for font, because you wouldn't want to have the text of the label written in the selected font. </p><h4>Remembering the Form Size and Position</h4><p>As mentioned before, a well-behaved application should remember its window placement and size. We can use the application settings for this as well. </p><p>First, define <strong>FormOptionsSize</strong> configuration value (of type <strong>System.Drawing.Size</strong>) and <strong>FormOptionsLocation</strong> (of type <strong>System.Drawing.Point</strong>). </p><p>The following code in the form's <strong>FormClosed </strong>event handler will save the window position and size when you close the window: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void FormOptions_FormClosed(object sender, 
    System.Windows.Forms.FormClosedEventArgs e)
{
    //  Save form size and position, if not minimized/maximized
    if (!(this.WindowState == FormWindowState.Normal))
    {
        return;
    }

    HiddenImage.Properties.Settings.Default.FormOptionsLocation = this.Location;
    HiddenImage.Properties.Settings.Default.FormOptionsSize = this.Size;
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub FormOptions_FormClosed(ByVal sender As Object,_
 ByVal e As System.Windows.Forms.FormClosedEventArgs)_
 Handles Me.FormClosed
    ' Save form size and position, if not minimized/maximized
    If Not Me.WindowState = FormWindowState.Normal Then Return
    My.Settings.FormOptionsLocation = Me.Location
    My.Settings.FormOptionsSize = Me.Size
End Sub
</pre></p><p>Note that we've added a condition that ensures that nothing is saved when a window is in a minimized or maximized state. That's because the <strong>Location</strong> and <strong>Size</strong> properties have awkward values in this case. The code can store the <strong>WindowState</strong> as well, but it's not usually a good idea to start an application minimized. (The user might think it hasn't been started at all.) </p><p>Now you need to make sure that the saved values are used when the form is open, and you can do this in the <strong>Load</strong> event handler. The selected font is displayed in the label as well. There is no need to load values of the selected files and so on, because they would automatically be loaded by data binding. </p><p><strong>C#</strong><br><pre class="brush: csharp">
private void FormOptions_Load(System.Object sender, System.EventArgs e)
{
    //  Setup form size and position
    this.Location = HiddenImage.Properties.Settings.Default.FormOptionsLocation;
    this.ClientSize = HiddenImage.Properties.Settings.Default.FormOptionsSize;

    //  Show font name and size in text form
    this.LabelFont.Text = string.Format(
        &quot;{0}, {1} pt&quot;,
        HiddenImage.Properties.Settings.Default.OverlayFont.Name,
        HiddenImage.Properties.Settings.Default.OverlayFont.SizeInPoints);
}</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub FormOptions_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                Handles MyBase.Load
    ' Setup form size and position
    Me.Location = My.Settings.FormOptionsLocation
    Me.ClientSize = My.Settings.FormOptionsSize

    ' Show font name and size in text form
    Me.LabelFont.Text = String.Format(&quot;{0}, {1} pt&quot;, My.Settings.OverlayFont.Name, _
         My.Settings.OverlayFont.SizeInPoints)
End Sub
</pre></p><h4>Playing the Game</h4><p>We have successfully created our application, which nicely resizes and remembers its configuration. That's good, but it's not good enough. We need the application to actually do what it was created for. So let's add a new form and name it <strong>FormGame</strong>. There's no need to do anything else with it for now. </p><p>Double-click the &quot;Start&quot; button in the main window and write few lines of code to display the newly created <strong>FormGame</strong>: </p><p><strong>C#</strong><br><pre class="brush: csharp"><span class="kwrd">private</span> <span class="kwrd">void</span> ButtonStart_Click(System.Object sender, System.EventArgs e)<pre class="csharpcode">{
    <span class="rem">//  Show game form</span>
    FormGame GameForm = <span class="kwrd">new</span> FormGame();
    GameForm.ShowDialog(<span class="kwrd">this</span>);
}</pre></pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub ButtonStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                                Handles ButtonStart.Click
    ' Show game form
    Dim GameForm As New FormGame
    GameForm.ShowDialog(Me)
End Sub
</pre></p><h4>Showing the Picture</h4><p>The actual game itself is created in the new form. Because we need to display the form in full-screen and without any borders, only the image is shown across entire screen. To achieve this, set the following properties of the <strong>FormGame</strong> form: </p><ul><li><pre class="csharpcode">FormBorderStyle = None</pre></li><li><pre class="csharpcode">ShowInTaskbar = False<br></pre></li><li><pre class="csharpcode">WindowState = Maximized</pre></li></ul><p>To display the selected picture, place a <strong>PictureBox</strong> on the form and in the Properties window find the <strong>Dock</strong> property and set the value to <strong>Fill</strong>. This property has a similar effect to <strong>Anchor</strong>: It causes the selected control to stick to one side of the form or, in case of the <strong>Fill </strong>setting, to fill entire form, which is exactly what's needed. Another solution would be to make the picture box the same size as the form and then set the <strong>Anchor</strong> property to all four sides. Using the <strong>Dock</strong> property is easier. </p><p>We need to show the picture resized to full screen, so set the <strong>SizeMode</strong> property to <strong>Zoom</strong>, which will ensure this behavior. </p><p>Then place the following code to the <code>Load</code> event handler of the form: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void FormGame_Load(System.Object sender, System.EventArgs e)
{
    //  Load image
    try
    {
        this.PictureBoxImage.Image = 
            Image.FromFile(HiddenImage.Properties.Settings.Default.ImageFilePath);
    }
    catch (Exception ex)
    {
        Interaction.MsgBox(&quot;Error loading image: &quot; &#43; ex.Message, 
            MsgBoxStyle.Exclamation, null);
        this.Close();
    }
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub FormGame_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)_
                                 Handles MyBase.Load
    ' Load image
    Try
        Me.PictureBoxImage.Image = Image.FromFile(My.Settings.ImageFilePath)
    Catch ex As Exception
        MsgBox(&quot;Error loading image: &quot; &amp; ex.Message, MsgBoxStyle.Exclamation)
        Me.Close()
    End Try
End Sub
</pre></p><p>As you see, you can directly use the value from <strong>My.Settings.ImageFilePath</strong> so that it automatically sets the file name selected by the user with the binding created earlier. </p><p>When doing anything with user-entered data, it's important to expect the worst possible error. The file specified may be corrupted, it may not actually be an image, or it may not even exist at all. The above code catches the possible exception thrown when a file cannot be read as image. </p><p>If you run the application now, it will display the selected an image in full-screen. You can close the message box window using ALT&#43;F4. </p><h4>Dynamically Generating Controls</h4><p>To cover the image, use <strong>Label</strong> controls. These must generate programmatically at runtime because you won't know during the design stage how many of them there will be. </p><p>A control is, from the code point of view, a class just like any other. You can create its instance and set its properties. You can extend the <strong>Load</strong> event handler using the following code: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void FormGame_Load(System.Object sender, System.EventArgs e)
{
    //  Generate basic overlay label width/height
    Int32 H = this.PictureBoxImage.Height / 
        System.Convert.ToInt32(HiddenImage.Properties.Settings.Default.Rows);
    Int32 W = this.PictureBoxImage.Width / 
        System.Convert.ToInt32(HiddenImage.Properties.Settings.Default.Columns);

    //  Create overlay labels
    for (int Y = 1; Y &lt;= System.Convert.ToInt32(
        HiddenImage.Properties.Settings.Default.Rows); Y&#43;&#43;)
    {
        for (int X = 1; X &lt;= System.Convert.ToInt32(
            HiddenImage.Properties.Settings.Default.Columns); X&#43;&#43;)
        {
            //  Create and place overlay label
            System.Windows.Forms.Label L = new System.Windows.Forms.Label();
            this.PictureBoxImage.Controls.Add(L);
            L.Left = (X - 1) * W;
            L.Top = (Y - 1) * H;
            L.Width = System.Convert.ToInt32(Interaction.IIf(
                X == HiddenImage.Properties.Settings.Default.Columns, 
                this.PictureBoxImage.Width - L.Left, W));
            L.Height = System.Convert.ToInt32(Interaction.IIf(
                Y == HiddenImage.Properties.Settings.Default.Rows,
                this.PictureBoxImage.Height - L.Top, H));

            //  Setup overlay label display
            L.Text = System.Convert.ToString((Y - 1) * 
                HiddenImage.Properties.Settings.Default.Columns &#43; X);
            L.BackColor = 
                HiddenImage.Properties.Settings.Default.OverlayBackgroundColor;
            L.ForeColor = 
                HiddenImage.Properties.Settings.Default.OverlayForegroundColor;
            L.Font = HiddenImage.Properties.Settings.Default.OverlayFont;
            L.TextAlign = ContentAlignment.MiddleCenter;
            L.BorderStyle = BorderStyle.FixedSingle;

            //  Attach event handlers
            L.Click &#43;= new System.EventHandler(ClickHandler);
            L.MouseEnter &#43;= new System.EventHandler(MouseEnterHandler);
            L.MouseLeave &#43;= new System.EventHandler(MouseLeaveHandler);
        }
    }

    //  Load image
    try
    {
        this.PictureBoxImage.Image = Image.FromFile(
            HiddenImage.Properties.Settings.Default.ImageFilePath);
    }
    catch (Exception ex)
    {
        Interaction.MsgBox(&quot;Error loading image: &quot; &#43; ex.Message, 
            MsgBoxStyle.Exclamation, null);
        this.Close();
    }
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub FormGame_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)_
                                 Handles MyBase.Load
    ' Generate basic overlay label width/height
    Dim H As Int32 = Me.PictureBoxImage.Height \ CInt(My.Settings.Rows)
    Dim W As Int32 = Me.PictureBoxImage.Width \ CInt(My.Settings.Columns)

    ' Create overlay labels
    For Y As Int32 = 1 To CInt(My.Settings.Rows)
        For X As Int32 = 1 To CInt(My.Settings.Columns)
            ' Create and place overlay label
            Dim L As New System.Windows.Forms.Label
            Me.PictureBoxImage.Controls.Add(L)
            L.Left = (X - 1) * W
            L.Top = (Y - 1) * H
            L.Width = CInt(IIf(X = My.Settings.Columns, Me.PictureBoxImage.Width - L.Left, W))
            L.Height = CInt(IIf(Y = My.Settings.Rows, Me.PictureBoxImage.Height - L.Top, H))

            ' Setup overlay label display
            L.Text = CStr((Y - 1) * My.Settings.Columns &#43; X)
            L.BackColor = My.Settings.OverlayBackgroundColor
            L.ForeColor = My.Settings.OverlayForegroundColor
            L.Font = My.Settings.OverlayFont
            L.TextAlign = ContentAlignment.MiddleCenter
            L.BorderStyle = BorderStyle.FixedSingle
        Next
    Next

    ' Load image
    Try
        Me.PictureBoxImage.Image = Image.FromFile(My.Settings.ImageFilePath)
    Catch ex As Exception
        MsgBox(&quot;Error loading image: &quot; &amp; ex.Message, MsgBoxStyle.Exclamation)
        Me.Close()
    End Try
End Sub
</pre></p><p>The only things left to solve are the width and height of the last labels. A control's size property must be an integer, and the screen resolution may not be evenly divisible by the number of squares. Actually the size of the squares at the bottom and to the right of the screen are not the same as the others that fill the remaining space. If this weren't the case, we would be able to see a few pixels of the picture underneath on the right and bottom sides. If you run the aplication now, you'll see no image, only the numbered grid.</p><h4>Make the Squares Live</h4><p>A particular square should hide itself when clicked. To achieve this use the <strong>Click</strong> event handler with the following code: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void ClickHandler(object sender, EventArgs e)
{
    //  Make label transparent (leave only border)
    System.Windows.Forms.Label L = ((System.Windows.Forms.Label)(sender));
    L.BackColor = Color.Transparent;
    L.Text = &quot;&quot;;
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub ClickHandler(ByVal sender As Object, ByVal e As EventArgs)
    ' Make label transparent (leave only border)
    Dim L As System.Windows.Forms.Label = DirectCast(sender, System.Windows.Forms.Label)
    L.BackColor = Color.Transparent
    L.Text = &quot;&quot;
End Sub
</pre></p><p>The squares should also indicate visually when the mouse pointer moves over them. A good visual cue is to swap the squares' foreground and background colors. There are two methods for doing this: </p><p><strong>C#</strong><br><pre class="brush: csharp">private void MouseEnterHandler(object sender, EventArgs e)
{
    //  Invert color on hover, if label is not revealed
    System.Windows.Forms.Label L = ((System.Windows.Forms.Label)(sender));
    if (L.BackColor == Color.Transparent)
    {
        return;
    }

    L.BackColor = HiddenImage.Properties.Settings.Default.OverlayForegroundColor;
    L.ForeColor = HiddenImage.Properties.Settings.Default.OverlayBackgroundColor;
}

private void MouseLeaveHandler(object sender, EventArgs e)
{
    //  Return color on hover end, if label is not revealed
    System.Windows.Forms.Label L = ((System.Windows.Forms.Label)(sender));
    if (L.BackColor == Color.Transparent)
    {
        return;
    }

    L.BackColor = HiddenImage.Properties.Settings.Default.OverlayBackgroundColor;
    L.ForeColor = HiddenImage.Properties.Settings.Default.OverlayForegroundColor;
}
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">Private Sub MouseEnterHandler(ByVal sender As Object, ByVal e As EventArgs)
    ' Invert color on hover, if label is not revealed
    Dim L As System.Windows.Forms.Label = DirectCast(sender, System.Windows.Forms.Label)
    If L.BackColor = Color.Transparent Then Return
    L.BackColor = My.Settings.OverlayForegroundColor
    L.ForeColor = My.Settings.OverlayBackgroundColor
End Sub

Private Sub MouseLeaveHandler(ByVal sender As Object, ByVal e As EventArgs)
    ' Return color on hover end, if label is not revealed
    Dim L As System.Windows.Forms.Label = DirectCast(sender, System.Windows.Forms.Label)
    If L.BackColor = Color.Transparent Then Return
    L.BackColor = My.Settings.OverlayBackgroundColor
    L.ForeColor = My.Settings.OverlayForegroundColor
End Sub
</pre></p><p>Next let's &quot;wire&quot; the methods specified above to run at the right moment. You can use the <strong>AddHandler</strong> command for this while generating the controls. Change the <strong>FormGame_Load</strong> method by entering the following code to the inner loop (right after line <code>L.BorderStyle = BorderStyle.FixedSingle</code>): </p><p><strong>C#</strong><br><pre class="brush: csharp">//  Attach event handlers
L.Click &#43;= new System.EventHandler(ClickHandler);
L.MouseEnter &#43;= new System.EventHandler(MouseEnterHandler);
L.MouseLeave &#43;= new System.EventHandler(MouseLeaveHandler);
</pre><br><br><strong>Visual Basic</strong><br><pre class="brush: vb">' Attach event handlers
AddHandler L.Click, AddressOf ClickHandler
AddHandler L.MouseEnter, AddressOf MouseEnterHandler
AddHandler L.MouseLeave, AddressOf MouseLeaveHandler
</pre></p><p>These methods will handle the events of all the label controls. The <strong>source</strong> parameter indicates which particular control caused the event. </p><p>The application is almost complete. If we run it now, the squares will hide when they are clicked, and that's what we want. </p><h4>Catching the Keys</h4><p>As mentioned earlier, pressing the ENTER key should reveal the entire image, while pressing the ESC key should cancel the game. So, how to you achieve this? By using the form's <strong>KeyDown</strong> event. Attach the following code to that method:<strong></strong></p><p><strong>C#</strong></p><pre class="csharpcode"><pre class="brush: csharp">
private void FormGame_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
    switch (e.KeyData)
    {
        case Keys.Escape:
        case Keys.Back:
            //  Close window
            this.Close();
            break;
        case Keys.Space:
        case Keys.Enter:
            //  Reveal image
            foreach (System.Windows.Forms.Control C in this.PictureBoxImage.Controls)
            {
                C.Hide();
            }
            break;
    }
}
</pre><br><br><pre class="csharpcode"><strong>Visual Basic</strong><br><pre class="brush: vb">
Private Sub FormGame_KeyDown(ByVal sender As Object,_
 ByVal e As System.Windows.Forms.KeyEventArgs)_
  Handles Me.KeyDown
    Select Case e.KeyData
        Case Keys.Escape
            ' Close window
            Me.Close()
        Case Keys.Enter
            ' Reveal image
            For Each C As Control In Me.PictureBoxImage.Controls
                C.Hide()
            Next
    End Select
End Sub
</pre><br></pre><br></pre><p>We did not hide the label controls completely in the per-square hiding code, but made their contents transparent to leave a border. In the new code revealing the entire image, we will hide them, to show the picture in all its beauty rather than with black grid bars over it. </p><h4>Conclusion</h4><p>I hope that by building this application along with me you have learned some useful things to help you in developing more complicated applications. </p><p>First, it is important to have a decent user interface — and it is easy and painless to achieve it with Microsoft .NET 2.0. Second, we reviewed how the application settings framework works and how you can easily manage configuration settings. Also you now know how to bind them to control properties and use them procedurally from the code. Third, we dynamically generated controls at run time, setting their properties and handling their events. And last but not at least, you have a fun game to play with friends. So, let's start!</p> <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michal-Altair-Valek/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:ba9de956278d4c1697bf9e7600dbbbc5">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Hidden-Image-Game</comments>
      <itunes:summary> In this article, we&#39;ll create a Hidden Image game. We&#39;ll demostrate few features available in Windows Forms in Microsoft .NET 2.0 for creating a consistent and user-friendly interface. Recently I was challenged to quickly write an application for playing the Hidden Image game, popularized here in the Czech Republic by a certain TV show. Luckily I had my notebook with Visual Basic Express at hand. This example shows how easy it is to write software in Visual Basic Express, and how to almost effortlessly create a well-behaved Windows application. It also demonstrates how to use certain new features available in Windows Forms in Microsoft .NET 2.0 for creating a consistent and user-friendly interface using the following techniques:  GUI design basics with Windows Forms Designer. Storing configuration settings for an application. Creating a borderless, full-screen window and dynamically generating controls in it. Rules of the GameHidden Image is not a computer game in the pure sense — it&#39;s more like a puzzle. Here&#39;s where a computer comes in handy, because it&#39;s simpler to show an image on the wall using a video projector than with cut paper cards (especially for us computer geeks, of course).)  To play the Hidden Image game, you need two opposite sides (players or teams) and one game master. The game master chooses an image. When displayed, the image is covered by numbered squares. Each player takes a turn removing one square, which reveals a portion of the image, and then attempts to guess what the image is. If the guess is correct, the player wins the game. If it&#39;s an incorrect guess, the other side takes a turn.  For this application I wanted to allow the game master to select the picture, set up certain parameters (like the number and color of the squares), and then display the covered picture. When clicking on any square, the square would disappear and reveal a part of the picture underneath. Pressing the ENTER key would reveal the entire picture, and pressing the</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Hidden-Image-Game</link>
      <pubDate>Tue, 31 Oct 2006 11:22:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Hidden-Image-Game</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/909778_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/909778_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michal Altair Val&#225;šek</dc:creator>
      <itunes:author>Michal Altair Val&#225;šek</itunes:author>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Hidden-Image-Game/RSS</wfw:commentRss>
    </item>    
</channel>
</rss>