Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm General / December 2004

Tip: Looking for answers? Try searching our database.

Determine scrolling in MDI Form MdiClient

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Mike in Paradise - 11 Dec 2004 08:07 GMT
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[i] 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;
}
}                                              
}
}
Mike in Paradise - 12 Dec 2004 18:55 GMT
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[i] 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();
}
}
}

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.