Welcome to MSDN Blogs Sign in | Join | Help

jfo's coding

adventures in windows forms and wpf
Goodbye Redmond

In January, I'll be hanging up my keyboard for a while as I move to Australia.  I have really enjoyed my work at Microsoft; particularly with my team, which is filled with smart, talented folk who really care about doing the right thing. 

This will be my last post to blogs.msdn.com.  If you want to keep up with me, my new blog address will be http://jfoscoding.blogspot.com (Feed). 

You may want to check out my new years resolutions and the advice I'd give myself if I were starting over.

Thanks for reading - and wish me luck! =)

 

Customer question roundup

I've been heads down working on a project lately, and I've let a few questions build up.  My apologies for this, here's what I have (if it's still useful):

Updates from Everen on fixing the disabled drawing for the ever-popular SplitButton sample.
I've just wanted to thank you for the SplitButton code. Only glitch was that it wasn't rendering correctly when it was Disabled so i've added a check at the start of the OnPaint function to set the _state to PushButtonState.Disabled. Also added checks at the arrow and text rendering lines to render in Control.GrayText color.

Question on Control.Invoke
I'm surfing a treeview in a worker thread and I want to know if it's better to use Control.Invoke for this situation?
If you're not changing state, you might "get away" with this, but Invoke would ensure robustness as the treeview wont change out from underneath you.  The rule of thumb is touch the UI stuff only on the UI thread.  If you can use 2.0 try to keep CheckForIllegalCrossThreadCalls turned on.

Also, do you know if the "TreeNode.Tag" member (or any ".Tag" member of any control for that matter) needs to be invoked on the creating thread as well? Since this property really just stores raw programmer data I'm not sure if it's really necessary.

The "Tag" property is just an object.  But how you get a hold of the TreeNode on the secondary thread may be problematic (see the first response).  I would recommend keeping your data separate from your UI - use a hashtable or dictionary that both threads can look at - and take either locks as appropriate (if they're both using the same list) or use a BackgroundWorker style ReportProgress event:  the background thread presents a list which the UI thread copies and applies.

Question on ToolStripSettings
I was just wondering if there is anyway to save the Toolstrip to a non-default settings provider?
Unfortunately, this was an omission in the design.  You'd have to redo the settings persistence yourself.

Question on UnhandledExceptions
What exactly is an unhandled exception? Is this not a Unhadled Exception? if this is then why my ThreadException handler is not getting invoked?

try
{
   throw Exception();
}
//No catch block
finally
{

}

An Unhandled exception is when there is no catch block in the callstack.  If you're using the System.Windows.Forms.Application.ThreadException event to trap unhandled exceptions, you should know that the "catch" block under the covers only works when the message pump has already been started.  So if you throw from main before Application.Run or in the constructor while creating the argument you're passing into Application.Run or throw from a background thread, the ThreadException dialog might not be there for you.  Here's an example:

using System;
using System.Windows.Forms;

namespace Test {

   public class Form1 : Form {

       public Form1() {
         // This object isn't run under the message loop yet!  Application.Run hasn't been called! 
         try  {
            throw new Exception();
          }
          //No catch block
          finally {
          }
       }

       [STAThread]
       public static void Main() {
          // how it's typically written
          Application.Run(new Form1());

         // another way of writing the same code is:

         // Form1 f = new Form1();
         // Application.Run(f);

  
       }
   }
}


If you hook onto a few more things, you can get a more systematic approach to catching errors outside the message loop.

Happy Holidays!
JFo

 

Bloopers and Outtakes

I've been going through some older stuff, and I found a few "unpublished" works, which I'm posting for you as-is, un-edited, in all it's glory. 

The Painting Stages of the ToolStrip Renderer
Discusses the ordering of calls to the layers of the toolstrip renderer so you know what to override if you want to make a custom renderer.

Building a TabStrip from a ToolStrip (sample)
Discusses how to tweak the layout and painting of your toolstrip in very advanced ways to make a tab control.  Also discusses how to add some designer features.

Using TableLayoutPanel Walkthrough
Ooops! Guess what I forgot to add to the password dialog box... oh well, at least you'll see how to fiddle with columns and rows.
 

 

Grabbing .dmp files from crash dialogs

If you're a company wanting to get access to the data from the crash dialog, this article isn't for you.  But this is

Also, I am not an expert in this topic.

Now that that is off my chest, and we've all had fair warning, here's my scenario:  I've done something in an application that's caused it to crash and I get the "SomeProgram has encountered a problem and needs to close.  We are sorry for this inconvenience."  If you click on the "What data does this error report contain?" link, you'll notice it's also created a crash dump of the process. 

A couple of times I've wanted to look at the dump file that's sent to the Online Crash Analysis to see if it was my code on the stack.  Maybe it's a hard-to-repro thing, or maybe it doesn't repro under the debugger, yada yada.

Frustratingly, it's nearly impossible to get at that .dmp file.  If you happen to find it, you can't copy it aside.  And if you look for it after dismissing the dialog, the .dmp file has been deleted from the machine.

Or so I thought.  Here's the trick that worked for me on Windows XP Professional: use the backup utility to back up the .dmp file, then open it in Visual Studio or Windbg.  (I welcome anyone else's suggestions for a less painful process)

Creating an app that shows the dialog
(you can skip this step if you already have a crashy app).

  • Create a new Windows Forms Application in Visual Studio 2005
  • In Program.cs, add the following line before Application.Run
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
  • Add a button to the form in the designer, double click on it and add the following code:
            private void button1_Click(object sender, EventArgs e) {
                throw new Exception("crash!");
            }
  • Control + F5 (run without debugging) your new crash-tastic application

When you click the button you should now see the famous dialog.  DON'T close it or you'll lose the .dmp!

Finding the .dmp file

It should be in your temp folder.  Here's how I find it quickly:

  • Start up a windows explorer (Windows+E) and put %TEMP% in your address bar to navigate to your temp dir
  • View->Details to get the timestamps of all the files in your temp directory
  • Click on the DateModified column to sort by date
  • Look for a .dmp file that would be close to when you thought you crashed the app

Verify you can't copy the file..

  • Try to copy/paste the .dmp file in Windows Explorer.

Now you see what I mean. (Cannot copy A8E2728: It is being used by another person or program.)  If you wait for the crash dialog to go away, the .dmp file will be removed from your machine.  So we have to take action now.

Open up the Backup utility

  • Start->All Programs->Accessories->System Tools->Backup
  • If you get the "Welcome to the Backup or Restore Wizard", swap to "Advanced Mode"
  • Once you're in "Advanced Mode", click on the "Backup" tab.

Back up the .dmp file (you'll have to back up the entire temp dir)

  • Navigate to the C:\Documents and Settings\JFo\Local Settings\Temp folder on the left hand tree.
  • Click on the checkbox for the temp folder in the left hand tree
  • In the right hand list, uncheck all the subfolders (e.g (C:\Documents and Settings\JFo\Local Settings\Temp\tempdir\))
  • Don't worry if there is no checkmark next to the .dmp file itself - it seems to work on folders specifically.
  • Click the "Browse..." button at the bottom of the dialog to pick the .bkf file to back up to (e.g. c:\BackupDumpFile.bkf)
  • Click the "Start Backup" button
  • In the "Backup Job Information" dialog, click "Start Backup"

Restoring the .dmp file from backup

  • In the backup utility, click the "Restore and Manage Media" option
  • Expand File in the left hand tree and navigate to BackupDumpFile.bkf
  • Expand "c:", "Documents and Settings", etc... until you get to the Temp folder.
  • When you've expanded the Temp folder, look for your .dmp file (if you click the modified column it will likely sort near the top)
  • Check the .dmp file on the right hand side
  • In the "Restore Files To" combo box, swap "Original location" to "Alternate location"
  • Click the "Browse..." button to pick a different folder or type in a new folder, e.g. "C:\tempbackup"
  • STOP!  Double check the settings to make sure you're restoring to the right spot and you have a warm and fuzzy feeling!
  • Click the "Start Restore"
  • Accept "Confirm Restore" dialog (if you're still feeling warm and fuzzy)

Look for the restored .dmp file on your disk:

  • Mine was restored to C:\tempbackup\Documents and Settings\Jessica\Local Settings\Temp
  • Open up windows explorer to find the file
  • If you have Visual Studio on your machine, double click it.  Otherwise open it up in Windbg (link below)
  • Hit F5 to run the dump file.

You should now see what state the program was in when it crashed - check the registers, get the call stack etc.

If you want to look at symbols, I'd recommend reading this article for how to set up the symbol server. You may also want to use strike to get a better picture of the CLR stack. In that case you may find using Windbg and SOS better.

For more information on working with .dmp files consult MSDN.

 

 

 


 

I'm a sloucher.

And now I can be ok with it.  Anyone got a protractor so I can measure off 135 degrees?

 

VB6/Winforms interop

Check out the Microsoft InteropForms Toolkit 1.0

This toolkit helps you bring the power of .NET to your existing VB6 applications, by allowing them to display .NET WinForms from within the same application. Instead of upgrading the entire code base, these applications can now be extended one form at a time. The goal is a phased upgrade, with production releases at the end of each iteration containing both VB6 and VB.NET forms running in the same VB6 .exe process.

Screencast available here: http://blogs.msdn.com/vbteam/archive/2006/09/23/768719.aspx

Josh seems to be having fun with Renderers

It looks like he's put together a very convincing VistaToolStripRenderer, and promises a tell-all series of articles. 

Stay tuned!

Sometimes I F5 when I meant to just compile.

Usually such a mistake is followed by a "noooooooooooooooooooooooooooooooooooo!" and quiet resignation to wait for my app to build and get to the point under the debugger where I can stop it. 

So here's a super-handy tip for larger projects I learned last week: You can cancel a build using CTRL+Break. 

I know you've all been wondering...
The answer is: October 6th.
Learning WPF

I’ve put together a series of articles on WPF, from a Windows Forms developer perspective.  This started out as a simple document entitled “So you know Windows Forms and you wanna learn Avalon” way before there was as much content out there as there is now.  I hope this twist in perspective is useful for folks. 

Enjoy!

 

 

[Update: MHT wasn't working out as well as I wanted, so you can now also just download the whole thing.]

Playing around with WPF/GDI+ Resource interop

WPF Resources

A while back, Jim posted a summary of the different types of resources in WPF.  We know that from the 1.0-2.0 versions of the .Net Framework, there were basically two ways to load an image from a resource: through .resx files and by directly adding them to the solution and changing the Build Action to “Embedded Resource”.

 

If you’ve ever tried to load a Bitmap in Windows Forms using the new Bitmap(typeof(MyType), “sunset.jpg”) constructor, you’ll appreciate that they wanted to do something more friendly for markup in WPF. 

 

In particular, its:

<Image Source="Sunset.jpg"/>

 

To make this work, you need to add an image to your project, and make sure (in the property grid) that the Build Action is set to Resource.

 

WPF/GDI+ Resource interop

The other day I ran into a situation where I wanted to potentially display an image in either WPF or in GDI/GDI+.  I wanted to have one way to specify the image, but the flexibility to use either technology to render the image.

 

The solution?  Use WPF’s new URI syntax and the helper methods on WPF’s application class to load the resource into a stream, then use the System.Drawing.Bitmap constructor that takes a stream.

 

I’ve put together a sample that shows how to load an GDI+ image from a WPF resource. 

 

I made several discoveries while writing this sample:

 

 

Michael Weinhardt has recently released a new article on resources. You should check out his new msdn magazine article on how pack uri’s work.

 

There’s kinda-sorta an alternate HBitmap solution.  If you’re starting with an HBitmap, you can use WPF’s System.Windows.Interop.Imaging methods such as CreateBitmapSourceFromHBitmap and friends. Unfortunately I couldn’t find a way to take a WPF image and scribble to an HBitmap.

 

Using the Loaded event for custom code is much more sane.  If you throw an exception in the constructor of the Window, you’re doing it in the XAML parser context – so you’ll get a XamlParseException, with your actual exception in the InnerException.

 

 

 

The sample

 

 

Lets walk through a sample interop case.  If you just want to see the code – skip to step 8.

 

Step 0: Install the latest version of Cider

Step 1: Create new WPF Windows application

Step 2: Right click on the project, surf to your sample images in My Pictures and add Sunset.jpg to the project

Step 3: Double check the properties window to ensure that the “Build Action” property for Sunset.jpg is set to “Resource”.

Step 4: Edit XAML.

 

<Window x:Class="WindowsApplication69.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication69" Height="300" Width="300"

    >

    <Grid>

      <Image Source="Sunset.jpg"/>

    </Grid>

</Window>

 

Step 5: Click back on the designer and verify that the image loads (this is a new feature in the latest CTP, enjoy!)

 

Step 6: Add the references we’re going to need to do some interop.  Expand the references section in the solution explorer and add a reference to:

System.Windows.Forms

System.Drawing

WindowsFormsIntegration

 

(look Program Files\Reference Assemblies\Microsoft\Framework\v3.0\ for the last one – it helps us use Windows Forms from WPF markup).

 

Step 7: (You’re still with me? Great!) Go back to XAML and add in the windows forms namespace to the window tag:

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

  

And then go ahead and add a WindowsFormsHost with a picture box in it.

      <WindowsFormsHost Width="100" Height="100" Background="Green">

        <wf:PictureBox x:Name="pictureBox"/>

      </WindowsFormsHost>

 

So that your final code looks like so:

 

<Window x:Class="WindowsApplication69.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

    Title="WindowsApplication69" Height="300" Width="300"

    >

    <Grid>

      <Image Source="Sunset.jpg"/>

      <WindowsFormsHost Width="100" Height="100" Background="Green">

        <wf:PictureBox x:Name="pictureBox"/>

      </WindowsFormsHost>

    </Grid>

</Window>

 

Step 8: Write code! Flip to Window1.xaml.cs.

 

public partial class Window1 : System.Windows.Window {

        public Window1() {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Window1_Loaded);

        }

 

        void Window1_Loaded(object sender, RoutedEventArgs e) {

            // build up a relative path to the image. 

            System.Uri imageLocation = new

                System.Uri("/WindowsApplication69;component/Sunset.jpg",

            System.UriKind.Relative);

            pictureBox.Image = GetBitmap(imageLocation);

                       

        }

 

        private System.Drawing.Bitmap GetBitmap(Uri uri) {

            // Use the helper methods on WPF's application

            // class to create an image.

            using (Stream resourceStream = Application.GetResourceStream(uri).Stream) {

                return new System.Drawing.Bitmap(resourceStream);

            }

        }

 

    }

 

 

 

 

Some of these pages are no longer intentionally left blank.

One thing we neglected to mention in the release notes is that you can now load up roots other than Window and Grid in the August CTP.  The list I believe is anything deriving from Panel, Page, UserControl and ContentControl. 

So if you have the latest installed - try replacing your window1.xaml with this:

<Button x:Class="WindowsApplication65.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
"
Height="75" Width="100"
>
Hello world!
</Button>

If you want to drag and drop into it, replace the contents with a Grid.  For button you may have to size the grid in code, as the button layout sizes grid to zero.

More interestingly, you can now design user controls.

<UserControl x:Class="WindowsApplication65.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="75" Width="100">
<
Grid>
</
Grid>
</
UserControl>

Have fun!

 

Scott starts blogging, and lets us know about Winforms/WPF gotchas
If you're doing Winforms and WPF you might just want to check it out.
Code maintenance tip, and why EventArgs are a good thing

…tap, tap, tap…  

 

I’ve been coding away lately and ran into one of those frustrating situations where I needed to add several new arguments to a function with a parameter list already a mile long.  That’s used in three places.  And I wasn’t sure what parameters I really needed.

 

public class A {

    public virtual object FooFunction (object foo, object bar, object baz, int foozle, int bazzle, int barrzle) {

    }

 

   public void FunctionThatCallsFooFunction(…) {

           // call the function with a lot of parameters

       FooFunction (foo, bar, baz, foozle, bazzle, barrzle);

   }

}

 

public class B : A {

     public overide object FooFunction (object foo, object bar, object baz, int foozle, int bazzle, int barrzle) {

    }

 

}

 

public class C : A {

     public overide object FooFunction (object foo, object bar, object baz, int foozle, int bazzle, int barrzle) { 

        // oops I need a FlibbertyGibbet and a WillOfAWhisp!

    }

 }

 

 

So when I had to add the second parameter, and was updating the function for the second time in the three places, I took a page out of the EventArgs book. 

 

public class A {

   public virtual object FooFunction (FunctionArgs args) {

   }

 

   public FunctionThatCallsFooFunction (…) {

           // call the function with a lot of parameters

       FooFunction (new FunctionArgs(foo, bar, baz, foozle, bazzle, barrzle));

   }

 

 

}

public class B : A {

    public overide object FooFunction (FunctionArgs args) {

    }

}

 

public class C : A {

    public overide object FooFunction (FunctionArgs args) {

         // now I can get FlibbertyGibbet and a WillOfAWhisp from args.FlibbertyGibbet!

    }

}

Where FunctionArgs is just a simple class:

 public class FunctionArgs {

   public FunctionArgs (object foo, object bar, object baz, int foozle, int bazzle, int barrzle) {

    //…

   }

   public object Foo {

   

   }

   … and so on

}

 

Now I can just add new properties to FunctionArgs and not have to update all the other classes (B, C, D, etc).

 

You see this pattern with events/delegates in the .Net Framework.  Deriving from EventArgs allows you to add new properties later on without updating all the places where the event is subscribed. 

 

e.g. The delegate (function signature) for MouseEventArgs is

    public delegate void MouseEventHandler(object sender, MouseEventArgs e);

 

There was nothing (besides the framework design guidelines)[1] that prevented us from writing the delegate this way:

 

public delegate void MouseEventHandler(object sender, MouseButtons button, int clicks, int x, int y, int delta);

 

…but if we wanted to do something like roll X & Y into a simple “Point location” parameter, we would have had to update all the places in the world that subscribe to mouse events.  

 

In v2 of Windows Forms, we simply added a new MouseEventArgs.Location property.  This allowed the old code to continue to work, and new code to use the handy helper property.

 

--

 

[1] Further notes from the Framework Design Guidelines

Consider using a derived class of System.EventArgs as the event argument, unless you are absolutely sure the event will never need to carry any data to the event-handling method, in which case you can use the System.EventArgs type directly.
If you define an event that takes an EventArgs instance instead of a derived class that you define, you cannot add data to the event in later versions. For that reason, it is preferable to create an empty derived class of EventArgs. This allows you add data to the event in later versions without introducing breaking changes.

 

Workaround for disabled flyouts

Frans ran into some trouble disabling parent menu items.  Turns out they dont disable the evaluation of child shortcuts.  This was an oversight on our part.  That said, most applications remove flyouts that are not in-use so as to not taunt users with menus they can't click on.  =)

 

Here's a quick workaround.  Add this to your project and replace your ToolStripMenuItems with this type.

 

Hope this helps! 

 

---

 

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows.Forms;

 

namespace WindowsApplication51 {

    /// <summary>

    /// Workaround for disabled flyout menus still evaluating shortcuts

    /// </summary>

    public class FullyEnabledMenuItem : ToolStripMenuItem {

        protected override bool ProcessCmdKey(ref Message m, Keys keyData) {

 

            if (!IsEveryoneEnabled()) {

                // store off the current state of enabled-ness

                bool isEnabled = Enabled;

                this.Enabled = false;

 

                // process the shortcut

                bool handled = base.ProcessCmdKey(ref m, keyData);

 

                // restore the state of enabledness

                this.Enabled = isEnabled;

 

                // return the result of processcmdkey

                return handled;

            }

            else {

                // everyone was enabled

                return base.ProcessCmdKey(ref m, keyData);

            }

        }

 

        private bool IsEveryoneEnabled() {

            if (!this.Enabled) {

                return false;

            }

 

            // walk up the owning item chain until the top

            ToolStripItem ownerItem = this.OwnerItem;

            while (ownerItem != null) {

                if (!ownerItem.Enabled) {

                    return