MDI Forms do not work correctly

Topics: Developer Forum
Jan 30, 2008 at 12:13 AM

I'm utilizing this work-around with the Smart Client Software Factory (for the Shell and my views)

The problem becomes evident by debugging the OnNonClientAreaHitTest(Point p) - the MDI Parent's button.Bounds will correctly hold it's coordinates but the MDI child will have incorrect values; the x and y coordinates are relative to itself where the received parameter (Point p), that it is compared to, are relative to the MDI Parent.

The workaround that I provide below will allow you to move and close a MDI Child form (these are all I required and time-constraints don't permit me to take it further); in addition, and for the same reason, I hard-coded the values to the stock "VistaForm" skin; you may need to tweak the values in the CompensateForMDI() method.

SkinRenderForm.cs

protected override int OnNonClientAreaHitTest(Point p)
{
    if (ActiveFormSkin == null)
        return (int)NativeMethods.NCHITTEST.HTCLIENT;
 
    foreach (CaptionButton button in this.CaptionButtons)
    {
        if (button.Visible && button.Bounds.Contains(p) && (button.HitTestCode > 0 || button.HitTestCode < -1))
            return button.HitTestCode;
    }
 



NonClientBaseForm.cs

CompensateForMDI() is a new method and the methods that implement this new method follow below:


protected Point CompensateForMDI(Point p)
{
    bool IsParent = Parent != null;
    if (IsParent)
    {
        p.X -= Parent.Parent.Location.X + 10;
        p.Y -= (Parent.Parent.Location.Y + 75);
    }
    return p;
}
 
 
private void WmNCHitTest(ref Message m)
{
    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputmessages/wm_nchittest.asp
 
    Point screenPoint = CompensateForMDI(new Point(m.LParam.ToInt32()));
 
    Log(MethodInfo.GetCurrentMethod(), string.Format("### Screen Point ({0},{1})", screenPoint.X, screenPoint.Y));
 
    // convert to local coordinates
    Point clientPoint = PointToWindow(screenPoint);
    Log(MethodInfo.GetCurrentMethod(), string.Format("### Client Point ({0},{1})", clientPoint.X, clientPoint.Y));
    m.Result = new System.IntPtr(OnNonClientAreaHitTest(clientPoint));
}
 
private void WmNCMouseMove(ref Message msg)
{
    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputmessages/wm_nchittest.asp
    Point clientPoint = CompensateForMDI(this.PointToWindow(new Point(msg.LParam.ToInt32())));
    OnNonClientMouseMove(new MouseEventArgs(MouseButtons.None, 0,
        clientPoint.X, clientPoint.Y, 0));
    msg.Result = IntPtr.Zero;
}
 
 
private void WmNCLButtonDown(ref Message msg)
{
    Point pt = CompensateForMDI(this.PointToWindow(new Point(msg.LParam.ToInt32())));
    NonClientMouseEventArgs args = new NonClientMouseEventArgs(
        MouseButtons.Left, 1, pt.X, pt.Y, 0, msg.WParam.ToInt32());
    OnNonClientMouseDown(args);
    if (!args.Handled)
    {
        DefWndProc(ref msg);
    }
    msg.Result = NativeMethods.TRUE;
}
 


SkinRenderForm.cs

The "|| Parent!=null" statement is the only change

protected override void OnNonClientMouseDown(NonClientMouseEventArgs args)
{
    if (args.Button != MouseButtons.Left)
        return;
 
    // custom button
    foreach (CaptionButton button in this.CaptionButtons)
        if (args.HitTest > short.MaxValue && args.HitTest == button.HitTestCode && button.Visible && button.Enabled)
        {
            ((CustomCaptionButton)button).OnClick();
            args.Handled = true;
            return;
        }
 
    // find appropriate button
    foreach (CaptionButton button in this.CaptionButtons)
    {
        // [1530]: Don't execute any action when button is disabled or not visible.
        if (args.HitTest == button.HitTestCode && button.Visible && button.Enabled)
        {
            Log(MethodInfo.GetCurrentMethod(), "MouseDown: button = {0}", button);
 
            if (DepressButton(button) || Parent!=null)
            {