Friday, 27 April 2007

Identifying if the next/s control in z order hides a given control

This is a quite simple c# class that lets identify if for a certain control, there is another above that hides the control (partially or completely, depending on the option).

I've uploaded a sample project here: Z order sample project

Here is the ZOrder class code:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;

namespace ZOrderFunctions
{
///
/// Defines helper function for testing zorder relationships
///

// By Javier Alvarez, 27 april 2007
class ZOrder
{
#region GetWindow
private const int GW_HWNDNEXT = 2;
private const int GW_HWNDPREV = 3;
private const int GW_CHILD = 5;


[DllImport("User32.dll")]
private static extern IntPtr GetWindow(IntPtr hwndSibling,
int wFlag);
//Parameters
//hWnd
//[in] Handle to a window. The window handle retrieved is relative to this window, based on the value of the uCmd parameter.
//uCmd
//[in] Specifies the relationship between the specified window and the window whose handle is to be retrieved. This parameter can be one of the following values.
//GW_CHILD
//The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
//GW_ENABLEDPOPUP
//Windows 2000/XP: The retrieved handle identifies the enabled popup window owned by the specified window (the search uses the first such window found using GW_HWNDNEXT); otherwise, if there are no enabled popup windows, the retrieved handle is that of the specified window.
//GW_HWNDFIRST
//The retrieved handle identifies the window of the same type that is highest in the Z order. If the specified window is a topmost window, the handle identifies the topmost window that is highest in the Z order. If the specified window is a top-level window, the handle identifies the top-level window that is highest in the Z order. If the specified window is a child window, the handle identifies the sibling window that is highest in the Z order.
//GW_HWNDLAST
//The retrieved handle identifies the window of the same type that is lowest in the Z order. If the specified window is a topmost window, the handle identifies the topmost window that is lowest in the Z order. If the specified window is a top-level window, the handle identifies the top-level window that is lowest in the Z order. If the specified window is a child window, the handle identifies the sibling window that is lowest in the Z order.
//GW_HWNDNEXT
//The retrieved handle identifies the window below the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window below the specified window. If the specified window is a top-level window, the handle identifies the top-level window below the specified window. If the specified window is a child window, the handle identifies the sibling window below the specified window.
//GW_HWNDPREV
//The retrieved handle identifies the window above the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window above the specified window. If the specified window is a top-level window, the handle identifies the top-level window above the specified window. If the specified window is a child window, the handle identifies the sibling window above the specified window.
//GW_OWNER
//The retrieved handle identifies the specified window's owner window, if any. For more information, see Owned Windows.
#endregion

///
/// Tells if the control is hidden by other in the z order
///

/// Control to be checked
/// if true, a control is returned even if it is only partially hidden, if false, the control must be completely hidden
/// If there is a control above, reference to the control
public static Control IsHidden(Control sender, bool partially)
{
// Check preconditions
if (sender == null) throw new ArgumentException("IsHidden recieved null as parameter");

// 'Found a control' flag
bool ret = false;

// Return value
Control topControl = null;

// Point to the display area rectangle
Rectangle senderRect = sender.DisplayRectangle; //new Rectangle(sRect.X, sRect.Y, sRect.Width, sRect.Height); senderRect.Location.Offset(
senderRect.Offset(sender.Left, sender.Top);

// Iterate through higher z-order controls to see if any above the sender control
IntPtr currentHandler = sender.Handle ;
Control currentControl = null;
do
{
// Get next control
currentHandler = GetWindow(currentHandler, GW_HWNDPREV);

if (currentHandler != IntPtr.Zero)
{
// Get associated rectangle
currentControl = Control.FromHandle(currentHandler);
Rectangle currentRectangle = currentControl.DisplayRectangle;
currentRectangle.Offset(currentControl.Left, currentControl.Top);

// Select if fully contained or partially
if (partially)
{
ret = currentControl.Visible && currentRectangle.IntersectsWith(senderRect);
}
else
{
ret = currentControl.Visible && currentRectangle.Contains(senderRect);
}
// Point to control if it matches the condition
if (ret)
{
topControl = currentControl;
}

}

} while (!ret && currentHandler != IntPtr.Zero);

return topControl;




}
}
}




Build a sample form with three buttons and add the following (or alike) code to test:

public partial class Form1 : Form
{



public Form1()
{
InitializeComponent();
}

private void Test(object sender)
{
Control top = ZOrder.IsHidden(sender as Control, true);
if (top != null)
{
MessageBox.Show("Handle of control above is : " + top.Handle.ToString());
}
else
{
MessageBox.Show("This control is the topmost");
}
}

private void button2_Click(object sender, EventArgs e)
{
Test(sender);
}

private void button1_Click(object sender, EventArgs e)
{
Test(sender);
}

private void button3_Click(object sender, EventArgs e)
{
Test(sender);
}

private void Form1_Load(object sender, EventArgs e)
{
button1.Text = button1.Handle.ToString();
button2.Text = button2.Handle.ToString();
button3.Text = button3.Handle.ToString();
}
}

No comments: