Tigraine

Daniel Hoelbling-Inzko talks about programming

Windows Forms: Form within a panel

I already blogged about Visual Inheritance as a tool for avoiding DRY violation.

Once you’re through with any better book on object oriented design you should have found another important oo principle:

Favor object composition over class inheritance

But how to do that in Windows Forms?
Well, if you dig with Reflector into the Form class you’ll discover that it’s derived from Control. And every container in Winforms accepts Control as it’s child objects.

image

Now, this makes it possible to just create a Panel and say:

panel1.Controls.Add(form);

But after running you’ll get a ArgumentException stating that you can’t add a top level control at this level.

The solution to this is even simpler, you simply need to tell the form to not be top level any more:

form.TopLevel = false;

And you’re done, you just need to set the BorderStyle on your form to get rid of the ugly borders and you’ve successfully embedded a form into another form.

The complete example looks like this:

Form1 form = new Form1();
form.TopLevel = false;
panel1.Controls.Add(form);
form.Show();

Common gotchas with Inherited Forms

Don’t repeat yourself is one of the most important principles I know of. And there are many ways to follow DRY when it comes to normal code.

But when you go to Winforms-land most people forget about DRY and create the same Gui code over and over again. Some of them are clever and abstract the “handlers” away from the buttons, but they still draw most of the buttons multiple times for forms that look almost exactly the same.

But it’s pretty common to have multiple views of the same forms. Like a CreateNewUser and a UpdateExistingUser mask, they both share almost all textboxes, but their values get processed differently.

You could try to use the same form for both operations, but that violates SRP (and makes things a lot harder), or you have two different forms that inherit the controls from a parent form.

Tha't’s then called Visual Inheritance. And, sadly the Windows Forms designer within Visual Studio is pretty bad at it, it crashed on my multiple times.

After 2 hours of fooling around with the Designer to get my Forms to show again I decided to share my experience, since there are some simple rules that you can follow to not break your design surface:

Don’t remove the default constructor from your parent form

The designer depends on a parameterless constructor, if you want to have parameters create a new constructor (and therefore don’t forget to call InitializeComponent again)

Don’t hook up Form_Load events in your parent form

I sincerely have no clue why this breaks the designer, but it does.

 

It’s rather tragic that the designer breaks on working code (compiling and running my code always worked, the designer just couldn’t load the form to show the design surface), but if you follow the above guidelines everything should work out fine.

There is also another way to remove code duplication by using Custom Controls and User Controls, these get handled better by the designer, but require a bit more thinking when creating (You may get in trouble when you try to modify their instantiation because that’s done during the InitializeComponent call).

DecimalTextbox for Windows Forms

I’ve been doing some Windows Forms development lately and really love it. After doing web development for the last couple of years I am thankful for the change. Being able to create compelling UIs without having to worry about Javascript is something I’ve been longing for quite some time.

But when trying to build intuitive and user-friendly UIs, you hit the boundaries of Microsoft’s control toolbox pretty fast. (Not as fast as with Webcontrols, but still).
I needed a Textbox that accepts only decimal input and that formats itself rather nicely for a finance application I’m building right now.

I first turned to the MaskedTextBox control that’s already there, but that turned out to be completely useless because numbers have no fixed length.
So I decided to create a Custom Control that derives from TextBox that does exactly what I need – take decimals and nothing else.

The whole process is rather simple, so I’ll just give you the code and be done with it. The DecimalTextbox control won’t accept any input that’s not numeric except for one comma. If you leave the control empty or non-decimal (however you accomplish that) it will revert to 0,00 on validation.

The code is after the break

public partial class DecimalTextBox : TextBox
{
    public DecimalTextBox()
    {
        InitializeComponent();
    }

    protected override void OnTextChanged(EventArgs e)     {         if (IsDecimal())             base.OnTextChanged(e);     }

    protected override void OnKeyPress(KeyPressEventArgs e)     {         if (!char.IsNumber(e.KeyChar)             && ((Keys)e.KeyChar != Keys.Back)             && (e.KeyChar != ','))             e.Handled = true;

        if (e.KeyChar == ',' && Text.IndexOf(',') > 0)             e.Handled = true;

        base.OnKeyPress(e);     }

    protected override void OnGotFocus(EventArgs e)     {         ResetValueOnFocus();         base.OnGotFocus(e);     }

    private void ResetValueOnFocus()     {         if (IsDecimal())         {             if (!IsDecimalZero())                 return;         }         Text = "";     }

    private bool IsDecimal()     {         decimal result;         return decimal.TryParse(Text, out result);     }

    private bool IsDecimalZero()     {         return (decimal.Parse(Text) == 0);     }

    private void DecimalTextBox_Validating(object sender, CancelEventArgs e)     {         decimal value;         decimal.TryParse(Text, out value);

        const string NUMBER_FORMAT_2_DIGITS = "N2";         Text = value.ToString(NUMBER_FORMAT_2_DIGITS);     }

    public decimal Value     {         get         {             return decimal.Parse(Text);         }     } }

And since copying source from HTML sucks here’s the DecimalTextBox.cs.

My Photography business

Projects

dynamic css for .NET

Archives

more