Click here to Skip to main content
13,557,745 members
Click here to Skip to main content
Add your own
alternative version


35 bookmarked
Posted 4 Mar 2004

SnapFormExtender - a magnet for your MDI child forms

, 4 Mar 2004
Rate this:
Please Sign up or sign in to vote.
An extender provider that draws MDI child forms to another form's edges while moving or resizing
Figure 1


Developing user interface we always wish to make it nice and neat. Of course, MDI application with accurately aligned child forms looks better but it's wastefulness to write heavy-weighting code for such trifles. That's why I decided to write a small and simple component that attracts a child form to the closest border while a user moves or resize it. Starting this work, I've set a few conditions for myself:

  • It should be an IExtenderProvider component in order to place it on the parent's form and forget about it
  • It shouldn't be a platform-dependent solution. I've refused to use Win32 API (though, I've regretted later)
  • To try to avoid overriding of WndProc because this code may interfere with already written one


At first, I've created IExtenderProvider component:

public class SnapFormExtender : Component, IExtenderProvider, ISupportInitialize

ISupportInitialize contains two methods: BeginInit() and EndInit(). I used the last one in order to hook event handler to the parent's form when initialization is completed. Then I've written CanExtend(object component) method that allows providing extender properties to the parent MDI form:

public bool CanExtend( object component )
   if( component is Form )
      Form form = ( Form )component;
      return form.IsMdiContainer;
   return false ;

Next, I've added three properties to the component:

  • Enabled - enable/disable to align child forms
  • Form - parent MDI form
  • Distance - maximum distance in pixels at which a child form will be attracted to a closest border

Every time a child form is activated, two event handlers will be added to the form:

private void parentForm_MdiChildActivate(object sender, EventArgs e)
   if( parentForm.ActiveMdiChild != null )
      Form child = parentForm.ActiveMdiChild;
      child.Move   -= new EventHandler(child_Move);
      child.Resize -= new EventHandler(child_Resize);
      if( enableSnap )
         child.Move   += new EventHandler(child_Move);
         child.Resize += new EventHandler(child_Resize);

Now we can control size and movement of the child form. Using our event handlers we intercept Control.Move and Control.Resize events. The last thing to do is to compare distance between our active child edge (formEdge1) and rest edges with the same orientation (see Figure 2).

Figure 2

If we find a closest edge at a range of the snap distance (property Distance), we move (or resize) our active form. So, the closest edges get the same coordinate and our forms become aligned. Pretty easily, isn't!

... and add it to your taste

Compile and run our test application SnapFormExtenderTest. If you create your own application using this component, you should add it to your VS toolbox:

  • Right-click on the "Windows Forms" tab in the Toolbox
  • Choose "Add/Remove Items..."
  • On the ".NET Framework Components", press the "Browse..." button and find a SnapFormExtender.dll

That will add a "SnapFormExtender" icon to the Windows Forms tab. Drag this icon to your MDI parent form. Select the snapFormExtender object on the Design View and set its Form property to your MDI parent form:

Figure 3

If you open InitializeComponent() source code, you will see something like this:

this.snapFormExtender = new SnapFormExtender.SnapFormExtender(this.components);
this.snapFormExtender.Form = this;
By default snap distance is 4 pixels. But you can change it at any time:
snapFormExtender.Distance = 6;     // Set snap distance to 6 pixels.
snapFormExtender.Enabled = false;  // Or disable it at all

I have added "Snap Distance" menu to the test - try to play with different values.

"I watch you move, so smooth..."

If you have started the test application, you've possibly noticed some funny thing. When you are trying to resize a child form pulling an edge that is already stuck to another border, the child form behaves like a caterpillar. While displacement is less than the snap distance, the border stays on place but the form changes its size. Very funny. But maybe you don't like it. Well, then just cut the SnapOnResize() out or decrease the snap distance.

But seriously, the reason of that behavior is missing WM_SIZING, WM_MOVING, WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE events and corresponding event handlers for the Control component. Without it we cannot catch the moment when a user starts resizing. That's why I said I regret that rejected Win32 API. Next idea was to use PreFilterMessage(ref Message m). But after a few tests it's turned out that this filter doesn't monitor all necessary messages. Overriding WndProc or setting event hook with SetWindowsHookEx() I would make the code rather awkward and difficult to build into new projects.

Anyway, I think this component has a reasonable balance of simplicity in use and functionality.


  • March 4th, 2004 - First release.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Jevgenij lives in Riga, Latvia. He started his programmer's career in 1983 developing software for radio equipment CAD systems. Created computer graphics for TV. Developed Internet credit card processing systems for banks.
Now he is System Analyst in Accenture.

You may also be interested in...


Comments and Discussions

GeneralThank you Pin
El Chubb25-Jun-09 18:25
memberEl Chubb25-Jun-09 18:25 
GeneralRe: Thank you Pin
El Chubb25-Jun-09 18:38
memberEl Chubb25-Jun-09 18:38 
QuestionLicense? Pin
Member 417923026-Feb-09 0:59
memberMember 417923026-Feb-09 0:59 
AnswerRe: License? Pin
Eugene Pankov26-Feb-09 6:36
memberEugene Pankov26-Feb-09 6:36 
GeneralRe: License? Pin
Member 417923026-Feb-09 8:54
memberMember 417923026-Feb-09 8:54 
GeneralVery adaptable Pin
GravitySpec16-Jan-07 12:06
memberGravitySpec16-Jan-07 12:06 
GeneralSimilar ... Pin
Tutu26-Apr-04 19:21
memberTutu26-Apr-04 19:21 
GeneralRe: Similar ... Pin
lecobf17-Jan-06 5:12
memberlecobf17-Jan-06 5:12 
GeneralRe: Similar ... Pin
glacialfury20-Jul-06 11:33
memberglacialfury20-Jul-06 11:33 
GeneralQuite Helpful Pin
surgeproof12-Mar-04 7:43
membersurgeproof12-Mar-04 7:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02-2016 | 2.8.180515.1 | Last Updated 5 Mar 2004
Article Copyright 2004 by Jevgenij Pankov
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid