I'd agree with Matt. Setting the "MaximizedBounds" is not a good idea.
As written in http://stackoverflow.com/questions/1295999/event-when-a-window-gets-maximized-un-maximized, I would override the WndProc-method. There you can handle the different received commands from your window on your own.
The main thing to do is to write your own code for the "SC_MAXIMIZE"-windowcommand (as written in the referenced article above). There you can manually set the form's size e.g. In this case the form won't be really maximized. Actually is it still in normal WindowState. To prevent the user from changing this state you need to "catch" some other windowcommands.
The overridden WndProc method could be like this:
protected override void WndProc(ref Message m)
{
if(m.Msg == 0x0112) // WM_SYSCOMMAND
{
if(m.WParam == new IntPtr(0xF012)) //TITLE_CLICK_ONCE
{
// catch, this command can occur, when form starts to move
}
if(m.WParam == new IntPtr(0xF001) // RESIZE_ON_EDGE
|| m.WParam == new IntPtr(0xF002)
|| m.WParam == new IntPtr(0xF003)
|| m.WParam == new IntPtr(0xF004)
|| m.WParam == new IntPtr(0xF005)
|| m.WParam == new IntPtr(0xF006)
|| m.WParam == new IntPtr(0xF007)
|| m.WParam == new IntPtr(0xF008))
{
// catch the resizing
}
if(m.WParam == new IntPtr(0xF032)) // SECOND_CLICK_ON_TITLEBAR
{
// catch. causes a maximization (or resuming to normal window-mode)
}
if(m.WParam == new IntPtr(0xF030)) //SC_MAXIMIZE
{
// the actual point, where to enter your code
// this command occurs, when the "Maximize"-button is pressed
}
}
// maybe abort calling of the base-method at specified window-commands,
// when you want to make your own code by simply "return;"
base.WndProc(ref m);
}