vbAccelerator - Contents of code file: SizingMovingSubclass.csusing System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace vbAccelerator.Components.SubClassExamples
{
// note that in this example I'm using Interfaces
// to notify the caller of a change. However, you
// could equally use events for the notifications,
// there is just a little more overhead that way.
#region Sizing/Moving Subclass
/// <summary>
/// Enumeration of reason for WM_SIZE message
/// </summary>
public enum SizedReasonTypes
{
/// <summary>
/// Message is sent to all pop-up windows when some
/// other window is maximized.
/// </summary>
SIZE_MAXHIDE = 4,
/// <summary>
/// The window has been maximized.
/// </summary>
SIZE_MAXIMIZED = 2,
/// <summary>
/// Message is sent to all pop-up windows when some other window
/// has been restored to its former size.
/// </summary>
SIZE_MAXSHOW = 3,
/// <summary>
/// The window has been minimized.
/// </summary>
SIZE_MINIMIZED = 1,
/// <summary>
/// The window has been resized, but neither the SIZE_MINIMIZED
/// nor SIZE_MAXIMIZED value applies.
/// </summary>
SIZE_RESTORED = 0
}
/// <summary>
/// Enumeration of location from which sizing is taking place
/// </summary>
public enum SizingLocationTypes
{
/// <summary>
/// Bottom edge
/// </summary>
WMSZ_BOTTOM = 6,
/// <summary>
/// Bottom-left corner
/// </summary>
WMSZ_BOTTOMLEFT = 7,
/// <summary>
/// Bottom-right corner
/// </summary>
WMSZ_BOTTOMRIGHT = 8,
/// <summary>
/// Left edge
/// </summary>
WMSZ_LEFT = 1,
/// <summary>
/// Right edge
/// </summary>
WMSZ_RIGHT = 2,
/// <summary>
/// Top edge
/// </summary>
WMSZ_TOP = 3,
/// <summary>
/// Top-left corner
/// </summary>
WMSZ_TOPLEFT = 4,
/// <summary>
/// Top-right corner
/// </summary>
WMSZ_TOPRIGHT = 5
}
/// <summary>
/// Interface for receiving Sizing and Moving notifications
/// </summary>
public interface ISizingMovingNotify
{
/// <summary>
/// Notifies of a window sizing attempt.
/// </summary>
/// <param name="rectangle">Proposed new window rectangle; can be
modified</param>
/// <param name="sizingLocation">Location from which sizing is taking
place</param>
void Sizing(ref System.Drawing.Rectangle rectangle,
SizingLocationTypes sizingLocation);
/// <summary>
/// Notifies of a window moving attempt.
/// </summary>
/// <param name="rectangle">Proposed new window rectangle; can be
modified</param>
void Moving(ref System.Drawing.Rectangle rectangle);
/// <summary>
/// Notifies of a window move.
/// </summary>
/// <param name="rectangle">New window rectangle.</param>
void Moved(System.Drawing.Rectangle rectangle);
/// <summary>
/// Notifies of a windows change in size.
/// </summary>
/// <param name="rectangle">New window rectangle.</param>
/// <param name="reason">Reason for size change</param>
void Sized(System.Drawing.Rectangle rectangle,
SizedReasonTypes reason);
}
/// <summary>
/// Class for intercepting sizing and moving events for
/// a window.
/// </summary>
public class SizingMovingSubclass :
System.Windows.Forms.NativeWindow,
IDisposable
{
/// <summary>
/// User defined data
/// </summary>
private object tag = null;
/// <summary>
/// Object to notify when window moves or sizes
/// </summary>
private ISizingMovingNotify notify = null;
/// <summary>
/// Message send during sizing operations
/// </summary>
private const int WM_SIZING = 0x0214;
/// <summary>
/// Message send during moving operations
/// </summary>
private const int WM_MOVING = 0x0216;
/// <summary>
/// Message sent after window has been moved.
/// </summary>
private const int WM_MOVE = 0x3;
/// <summary>
/// Message sent after window has been sized.
/// </summary>
private const int WM_SIZE = 0x5;
/// <summary>
/// Private structure for interoperability
/// </summary>
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public override string ToString()
{
return string.Format("RECT: ({0},{1})-({2},{3})",
this.left, this.top, this.right, this.bottom);
}
}
[DllImport("user32")]
private static extern int GetWindowRect(
IntPtr handle,
ref RECT rc);
/// <summary>
/// Gets/sets a user-defined object associated with the class
/// </summary>
public object Tag
{
get
{
return this.tag;
}
set
{
this.tag = value;
}
}
/// <summary>
/// Gets/sets the interface to notify of moving or sizing
/// </summary>
public ISizingMovingNotify Notify
{
get
{
return this.notify;
}
set
{
this.notify = value;
}
}
/// <summary>
/// Processes window messages and notifies of any sizing
/// moving events.
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref System.Windows.Forms.Message m)
{
RECT rc = new RECT();
GetWindowRect(m.HWnd, ref rc);
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
// If message is a size/move message and a notifier
// is in place then notify it:
switch (m.Msg)
{
case WM_SIZING:
rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
if (notify != null)
{
rectangle = new System.Drawing.Rectangle(
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
notify.Sizing(ref rectangle,
(SizingLocationTypes)((int)m.WParam));
rc.left = rectangle.Left;
rc.top = rectangle.Top;
rc.right = rectangle.Right;
rc.bottom = rectangle.Bottom;
}
Marshal.StructureToPtr(rc, m.LParam, true);
m.Result = (IntPtr)1; // TRUE
break;
case WM_MOVING:
rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
if (notify != null)
{
rectangle = new System.Drawing.Rectangle(
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
notify.Moving(ref rectangle);
rc.left = rectangle.Left;
rc.top = rectangle.Top;
rc.right = rectangle.Right;
rc.bottom = rectangle.Bottom;
}
Marshal.StructureToPtr(rc, m.LParam, true);
m.Result = (IntPtr)1; // TRUE
break;
case WM_SIZE:
base.WndProc(ref m);
if (notify != null)
{
// get width/height from lParam:
rectangle.Width = (int)((uint)m.LParam & 0xFFFF);
rectangle.Height = (int)(((uint)m.LParam & 0xFFFF0000) << 16);
notify.Sized(rectangle,
(SizedReasonTypes)((int)m.WParam));
}
break;
case WM_MOVE:
base.WndProc(ref m);
if (notify != null)
{
rectangle.X = (int)((uint)m.LParam & 0xFFFF);
rectangle.Y = (int)(((uint)m.LParam & 0xFFFF0000) << 16);
notify.Moved(rectangle);
}
break;
default:
base.WndProc(ref m);
break;
}
}
/// <summary>
/// Clears up resources associated with this object
/// </summary>
public void Dispose()
{
if (this.Handle != IntPtr.Zero)
{
this.ReleaseHandle();
}
}
/// <summary>
/// Creates a new instance of the SizingMovingSubclass
/// object and starts checking for sizing and moving
/// </summary>
/// <param name="handle">Handle of window to check for
/// sizing/moving</param>
/// <param name="tag">User defined data</param>
/// <param name="notify">Object to receive sizing/moving
/// notifications</param>
public SizingMovingSubclass(
IntPtr handle,
object tag,
ISizingMovingNotify notify)
{
this.AssignHandle(handle);
this.tag = tag;
this.notify = notify;
}
}
#endregion
}
|
|