Determine scrolling in MDI Form MdiClient

Discussion in 'Microsoft Dot NET Framework Forms' started by Guest, Dec 11, 2004.

  1. Guest

    Guest Guest

    I have been racking my brains trying to figure out how to know when you have
    scrolled the MdiClient window on an MDI form. (Not an MdiChild Window) I
    have tried monitoring the messages for both the MdiClient and the MdiForm
    itself..

    I put a IFilterMessage as well well as overriding the WndProc on the the
    mainform to see all messages going by and Identifiying the MdiClient
    Messages..

    When you click on the ScrollBar you get..

    MdiClient->WM_NCLBUTTONDOWN

    There is not a corresponding up button message or a WM_HSCROLL message.

    Form that point you get no further messages in the MdiForms WndProc or the
    IMessageFilters.PreveiwMessage until you release the mouse and then you get
    either:

    1) If you are clicked on the scrollbar and move the cursor,either to a
    status bar or other neighboring control below it before you release the
    mouse the next message appears to be a WM_MOUSEMOVE on the status bar or
    other control

    2) If you release the mouse in the scroll bar is issue the MdiClient a
    WM_Paint but it doesn't always do a complete repaint which results in any
    background painting of the MdiClient being messed up when scrolling has
    occurred...

    3) If you release back into the MdiClient widow you get a WM_SetCursor
    message and again it doesn't do a complete repaint which results in any
    background painting of the MdiClient being messed up.

    Any ideas on you tell when you have scolled the MdiClient on a MdiParent
    form?? What I want to be able to do is when the MdiClient has been Scrolled
    to completely invalidate it and repaint it so the background is intact...

    I found several discussions on various forums including one where they are
    saying to Invalidate it completely on the first MdiChild paint attempt,
    which cause the background to paint ok but it flickers badly.

    I used the code below found on the web to cause painting of the MdiChild
    background..

    Thanks..

    // This code stops the background repainting of the MdiClient from flickering
    // as it sets the Double Buffering in MdiClient when doesnt set properly
    // .From an Article at
    // http://www.codeproject.com/csharp/MdiClientRevisited.asp#xx948448xx

    [DefaultValue(false)]
    public new bool IsMdiContainer
    {
    get{ return base.IsMdiContainer; }
    set
    {
    base.IsMdiContainer = value;

    if( ! value) return;

    for(int i = 0; i < this.Controls.Count; i++)
    {
    MdiClient mdiClient = this.Controls as MdiClient;
    if(mdiClient != null)
    {
    ControlStyles styles = ControlStyles.DoubleBuffer;

    try
    {
    // Prevent flickering, only if our assembly
    // has reflection permission.
    Type mdiType = typeof(MdiClient);

    System.Reflection.BindingFlags flags =
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.Instance;

    System.Reflection.MethodInfo method
    = mdiType.GetMethod("SetStyle",flags);
    object[] param = {styles, true};
    method.Invoke(mdiClient,param);
    }
    catch ( System.Security.SecurityException)
    {
    /*Don't do anything!!! This code is running under
    partially trusted context*/
    }

    mdiClient.Paint +=new PaintEventHandler(this.MdiClient_Paint);
    mdiClient.Resize +=new EventHandler(MdiClient_Resize);
    break;
    }
    }
    }
    }
     
    Guest, Dec 11, 2004
    #1
    1. Advertisements

  2. Guest

    Guest Guest

    And NativeWindow is the Answer

    If anyone else is trying to to this, I came accross this excellent article..

    http://www.codeproject.com/csharp/MdiClientRevisited.asp#xx948448xx

    which used Native methods..

    The code below seems to let me track what the heck is happening in the
    MdiClient window...There is some use of internal Win32 routines for accessing
    and handling Windows Messages so you would have to change these but it will
    give you an idea as I have spent far too much time on this...

    //To use this
    MdiClientNativeWindow mdiClientNative = new MdiClientNativeWindow(this);
    mdiClientNative.Scrolled
    +=new EventHandler(MdiClient_Scrolled);
    mdiClientNative.MdiWindowPositionChanged
    +=new EventHandler(MdiClientNative_MdiWindowPositionChanged);


    //***************** MdiClientNativeWindow *****************
    using System;
    using System.Windows.Forms;
    using System.Diagnostics;
    using Bon.Win32;

    namespace Bon.Forms
    {
    /// <summary>
    /// Class: Provide access to an MdiClient in a MdiForm MdiClientNativeWindow.
    /// </summary>
    public class MdiClientNativeWindow: System.Windows.Forms.NativeWindow
    {
    /// <summary>
    /// Field: is MdiClient Vertical Scroll bar active
    /// </summary>
    private bool verticalScrollActive;
    /// <summary>
    /// Property: Gets if MdiClient Window is Scrolling Vertically
    /// </summary>
    public bool VerticalScrollActive
    {
    [DebuggerStepThrough()]
    get { return verticalScrollActive;}
    }
    /// <summary>
    /// Field: is MdiClient Horizontal Scroll bar active
    /// </summary>
    private bool horizontalScrollActive;
    /// <summary>
    /// Property: Gets if MdiClient Window is Scrolling Horizontally
    /// </summary>
    public bool HorizontalScrollActive
    {
    [DebuggerStepThrough()]
    get { return horizontalScrollActive;}
    }
    private Form parentForm;
    /// <summary>
    /// Property: Gets the Parent Form
    /// </summary>
    public Form ParentForm
    {
    [DebuggerStepThrough()]
    get { return parentForm;}
    }
    private MdiClient mdiClient;
    /// <summary>
    /// Property: Gets the MdiClient
    /// </summary>
    public MdiClient MdiClient
    {
    [DebuggerStepThrough()]
    get { return mdiClient;}
    }
    /// <summary>
    /// Event: MdiClient Window Position Changed (recieved WM_WINDOWPOSCHANGED)
    /// </summary>
    public event System.EventHandler MdiWindowPositionChanged;
    /// <summary>
    /// Event: MdiClient Set Cursor message (recieved WM_SETCURSOR)
    /// </summary>
    public event System.EventHandler MdiSetCursor;
    /// <summary>
    /// Event: MdiClient Window Activated (recieved WM_MDIGETACTIVE)
    /// </summary>
    public event System.EventHandler MdiGetActive;
    /// <summary>
    /// Event: MdiClient Window is About to Start Scrolling
    /// </summary>
    public event System.EventHandler ScrollingStarted;
    /// <summary>
    /// Event: MdiClient Window is Scrolling
    /// </summary>
    public event System.Windows.Forms.ScrollEventHandler Scrolling;
    /// <summary>
    /// Event: MdiClient Window has scrolled
    /// </summary>
    public event System.EventHandler Scrolled;
    /// <summary>
    /// Constructor: Default
    /// </summary>
    public MdiClientNativeWindow():this(null)
    {
    }
    /// <summary>
    /// Constructor: with Parent Form
    /// </summary>
    /// <param name="parentForm"></param>
    public MdiClientNativeWindow(Form parentForm)
    {
    this.verticalScrollActive = false;
    this.horizontalScrollActive = false;
    this.mdiClient = null;
    this.parentForm = parentForm;
    InitializeMdiClient();
    }

    protected override void WndProc(ref Message m)
    {
    try
    {
    WM msg = Win32API.Get_WM (m);
    Debug.WriteLine("MdiClientNativeWindow->"+msg.ToString() );
    switch (msg)
    {

    //This will check if scrolling Started
    case WM.WM_NCLBUTTONDOWN:
    MouseLeftClickNonClient(ref m);
    break;
    //Scolling progress and Completion will be triggered
    case WM.WM_VSCROLL:
    case WM.WM_HSCROLL:
    TriggerScrolling(ref m);
    break;
    //Consume this event to stop background Painting
    case WM.WM_ERASEBKGND:
    return;
    case WM.WM_SYNCPAINT:
    case WM.WM_PAINT:
    case WM.WM_MOVE:
    break;
    //Need to Trap this event So Background can be refreshed
    case WM.WM_MDIGETACTIVE:
    TriggerMdiGetActive();
    break;
    case WM.WM_SETCURSOR:
    TriggerMdiSetCursor();
    break;
    case WM.WM_WINDOWPOSCHANGED:
    TriggerMdiWindowPositionChanged();
    break;
    }
    }
    catch
    {
    }
    base.WndProc (ref m);
    }
    private void MouseLeftClickNonClient(ref Message m)
    {
    //Is Scroll Active
    if ( m.WParam == (IntPtr)HT.HTVSCROLL )
    {
    VerticalScrollActivated();
    }
    else if ( m.WParam == (IntPtr)HT.HTVSCROLL )
    {
    HorizontalScrollActivated();
    }
    }
    private void HorizontalScrollActivated()
    {
    horizontalScrollActive = true;
    TriggerScrollingStarted();

    }
    private void VerticalScrollActivated()
    {
    verticalScrollActive = true;
    TriggerScrollingStarted();

    }
    private void TriggerMdiWindowPositionChanged()
    {
    if (MdiWindowPositionChanged != null)
    {
    MdiWindowPositionChanged(this,new EventArgs() );
    }
    }
    private void TriggerMdiSetCursor()
    {
    if (MdiSetCursor != null)
    {
    MdiSetCursor(this,new EventArgs() );
    }

    }
    private void TriggerMdiGetActive()
    {
    if (MdiGetActive != null)
    {
    MdiGetActive(this,new EventArgs() );
    }

    }
    private void TriggerScrollingStarted()
    {
    if (ScrollingStarted != null)
    {
    ScrollingStarted(this,new EventArgs() );
    }

    }
    private void TriggerScrolled()
    {
    if (Scrolled != null)
    {
    Scrolled(this,new EventArgs() );
    }

    } /// <summary>
    /// Method: Triggers a Scroll Event and Monitors the Scroll requests
    /// looking for a SB_ThumbPostions so that
    /// a Scrolled message can be sent
    /// </summary>
    /// <param name="m"></param>
    private void TriggerScrolling(ref Message m)
    {
    //Monitor
    //
    //wParam The high-order word specifies the current position
    // of the scroll box if the low-order word
    // is SB_THUMBPOSITION or SB_THUMBTRACK;
    // otherwise, this word is not used.
    //
    //The low-order word specifies a scroll bar value that
    //indicates the user's scrolling request.
    //
    //This parameter can be one of the following values.
    //
    //SB_BOTTOM - Scrolls to the lower right.
    //SB_ENDSCROLL - Ends scroll.
    //SB_LINEDOWN - Scrolls one line down.
    //SB_LINEUP - Scrolls one line up.
    //SB_PAGEDOWN - Scrolls one page down.
    //SB_PAGEUP - Scrolls one page up.
    //SB_THUMBPOSITION - The user has dragged the scroll box (thumb)
    // and released the mouse button.
    // The high-order word indicates
    // the position of the scroll box at the end of the drag operation.
    //SB_THUMBTRACK - The user is dragging the scroll box.
    // This message is sent repeatedly until
    // the user releases the mouse button.
    // The high-order word indicates the position
    // that the scroll box has been dragged to.
    // SB_TOP
    // Scrolls to the upper left.
    //lParam
    //------
    //If the message is sent by a scroll bar,
    //this parameter is the handle to the scroll bar control.
    //If the message is not sent by a scroll bar,
    //this parameter is NULL.
    //
    ScrollEventArgs scrollArgs = ScrollArgsFromMessage(ref m);
    //Scroll Event
    if (this.Scrolling != null)
    {
    Scrolling(this.mdiClient,scrollArgs);
    }
    //This means the Scroll Bar has moved so Fired Completed Event
    if (scrollArgs.Type == ScrollEventType.ThumbPosition)
    {
    //Indicated Scolled before resetting flags..
    if (Scrolled != null)
    {
    Scrolled(mdiClient,new EventArgs() );
    }
    verticalScrollActive = false;
    horizontalScrollActive = false;
    }
    }
    /// <summary>
    /// Method: Create a Scroll Argument from a Windows Message
    /// </summary>
    /// <param name="m"></param>
    /// <returns></returns>
    private ScrollEventArgs ScrollArgsFromMessage(ref Message m)
    {
    //Scroll Button Enmeration...
    SB sb = (SB)Win32API.WParam_LoWord(m);

    ScrollEventType scrollType = (ScrollEventType)sb;
    //Position
    int scrollPosition = Win32API.WParam_HiWord(m);

    return new ScrollEventArgs(scrollType,scrollPosition);
    }
    private void InitializeMdiClient()
    {
    // If the mdiClient has previously been set, unwire events connected
    // to the old MDI.
    if(mdiClient != null)
    mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);

    if(parentForm == null)
    {
    return;
    }

    // Get the MdiClient from the parent form.
    for(int i = 0; i < parentForm.Controls.Count; i++)
    {
    // If the form is an MDI container, it will contain an MdiClient control
    // just as it would any other control.
    mdiClient = parentForm.Controls as MdiClient;
    if(mdiClient != null)
    {
    // Assign the MdiClient Handle to the NativeWindow.
    ReleaseHandle();
    AssignHandle(mdiClient.Handle);

    // Raise the HandleAssigned event.
    //OnHandleAssigned(EventArgs.Empty);

    // Monitor the MdiClient for when its handle is destroyed.
    mdiClient.HandleDestroyed += new EventHandler(MdiClientHandleDestroyed);
    }
    }
    }
    /// <summary>
    /// Method: MdiClient handle has been released, so drop the reference and
    /// release the handle.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void MdiClientHandleDestroyed(object sender, EventArgs e)
    {
    if(mdiClient != null)
    {
    mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);
    mdiClient = null;
    }
    ReleaseHandle();
    }
    }
    }
     
    Guest, Dec 12, 2004
    #2
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. KVullo

    Is there ANY way to have an MDI form INSIDE another MDI form?

    KVullo, Oct 20, 2003, in forum: Microsoft Dot NET Framework Forms
    Replies:
    3
    Views:
    641
  2. Trevor Germain

    System.Windows.Forms.MdiClient+ControlCollection not serializable.

    Trevor Germain, Nov 24, 2003, in forum: Microsoft Dot NET Framework Forms
    Replies:
    0
    Views:
    386
    Trevor Germain
    Nov 24, 2003
  3. Dan Burby

    This is how to change the 3d border on an MDIClient

    Dan Burby, Dec 19, 2003, in forum: Microsoft Dot NET Framework Forms
    Replies:
    0
    Views:
    2,581
    Dan Burby
    Dec 19, 2003
  4. Nathan Alden

    MdiClient border style

    Nathan Alden, Feb 21, 2004, in forum: Microsoft Dot NET Framework Forms
    Replies:
    1
    Views:
    294
    Herfried K. Wagner [MVP]
    Feb 21, 2004
  5. kstuver
    Replies:
    1
    Views:
    648
    Michael Höhne
    Dec 12, 2005
Loading...

Share This Page