using System;
using System.Windows.Forms;
using static Vanara.PInvoke.User32;
namespace Vanara.Extensions
{
/// Control extension methods.
public static partial class ControlExtension
{
///
/// Performs an action on a control after its handle has been created. If the control's handle has already been created, the action is executed immediately.
///
/// This control.
/// The action to execute.
public static void CallWhenHandleValid(this Control ctrl, Action action)
{
if (ctrl.IsHandleCreated)
{
action(ctrl);
}
else if (!ctrl.IsDesignMode())
{
void handler(object sender, EventArgs e)
{
if (!ctrl.IsHandleCreated) return;
ctrl.HandleCreated -= handler;
action(ctrl);
}
ctrl.HandleCreated += handler;
}
}
/// Enables all children of a control.
/// This control.
/// If set to true enable all children, otherwise disable all children.
public static void EnableChildren(this Control ctl, bool enabled)
{
foreach (Control sub in ctl.Controls)
{
if (sub is ButtonBase || sub is ListControl || sub is TextBoxBase)
sub.Enabled = enabled;
sub.EnableChildren(enabled);
}
}
/// Gets the control in the list of parents of type T.
/// The based of the parent control to retrieve.
/// This control.
/// The parent control matching T or null if not found.
public static T GetParent(this Control ctrl) where T : class
{
var p = ctrl.Parent;
while (p != null & !(p is T))
p = p.Parent;
return p as T;
}
/// Gets the top-most control in the list of parents of type T.
/// The based of the parent control to retrieve.
/// This control.
/// The top-most parent control matching T or null if not found.
public static T GetTopMostParent(this Control ctrl) where T : class
{
var stack = new System.Collections.Generic.Stack();
var p = ctrl.Parent;
while (p != null)
{
stack.Push(p);
p = p.Parent;
}
while (stack.Count > 0)
if ((p = stack.Pop()) is T)
return p as T;
return null;
}
/// Gets the right to left property.
/// This control.
/// Culture defined direction of text for this control.
public static RightToLeft GetRightToLeftProperty(this Control ctrl)
{
while (ctrl != null)
{
if (ctrl.RightToLeft != RightToLeft.Inherit)
return ctrl.RightToLeft;
ctrl = ctrl.Parent;
}
return RightToLeft.No;
}
/// Determines whether this control is in design mode.
/// This control.
/// true if in design mode; otherwise, false.
public static bool IsDesignMode(this Control ctrl)
{
var p = ctrl;
while (p != null)
{
var site = p.Site;
if (site != null && site.DesignMode)
return true;
p = p.Parent;
}
return false;
}
///
/// Gets a string using a message pattern that asks for the string length by sending a GetXXXLen message and then a GetXXXText message.
///
/// The control.
/// The window message identifier for retrieving the string length.
/// The window message identifier for retrieving the string.
/// The string result from the message call.
public static string GetMessageString(this Control ctrl, uint getLenMsg, uint getTextMsg)
{
if (!ctrl.IsHandleCreated) return null;
var cp = ctrl.SendMessage(getLenMsg).ToInt32() + 1;
var sb = new System.Text.StringBuilder(cp);
Vanara.PInvoke.User32.SendMessage(ctrl.Handle, getTextMsg, ref cp, sb);
return sb.ToString();
}
/// Retrieves the window styles.
/// The control.
/// The window styles
public static int GetStyle(this Control ctrl) => GetWindowLongAuto(ctrl.Handle, WindowLongFlags.GWL_STYLE).ToInt32();
/// Removes the mnemonic, if one exists, from the string.
/// The string.
/// A mnemonic free string.
public static string RemoveMnemonic(this string str)
{
if (str == null) return null;
var idx = str?.IndexOf('&');
if (idx >= 0)
{
var sb = new System.Text.StringBuilder(str);
sb.Remove(idx.Value, 1);
return sb.ToString();
}
return str;
}
///
///
/// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not
/// return until the window procedure has processed the message.
///
///
/// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread's
/// message queue and return immediately, use the PostMessage or PostThreadMessage function.
///
///
///
///
/// A window whose window procedure will receive the message.
///
///
/// Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal
/// integrity level.
///
///
/// The message to be sent.
/// Additional message-specific information.
/// Additional message-specific information.
/// The return value specifies the result of the message processing; it depends on the message sent.
public static IntPtr SendMessage(this IWin32Window wnd, uint msg, IntPtr wParam = default, IntPtr lParam = default) =>
wnd.Handle != IntPtr.Zero && wnd.Handle.ToInt32() != -1
? Vanara.PInvoke.User32.SendMessage(wnd.Handle, msg, wParam, lParam)
: IntPtr.Zero;
/// Sets the windows styles.
/// The control.
/// The style flags.
/// if set to true add the style, otherwise remove it.
public static void SetStyle(this Control ctrl, int style, bool on = true)
{
var href = ctrl.Handle;
int oldstyle = GetWindowLongAuto(href, WindowLongFlags.GWL_STYLE).ToInt32();
if ((oldstyle & style) != style && on)
SetWindowLong(href, WindowLongFlags.GWL_STYLE, new IntPtr(oldstyle | style));
else if ((oldstyle & style) == style && !on)
SetWindowLong(href, WindowLongFlags.GWL_STYLE, new IntPtr(oldstyle & ~style));
ctrl.Refresh();
}
/// Converts a structure to a structure.
/// The MSG instance.
/// An equivalent structure.
public static Message ToMessage(this PInvoke.MSG msg) => Message.Create((IntPtr)msg.hwnd, (int)msg.message, msg.wParam, msg.lParam);
/// Converts a structure to a structure.
/// The Message instance.
/// An equivalent structure.
public static PInvoke.MSG ToMSG(this Message msg) => new PInvoke.MSG { message = (uint)msg.Msg, hwnd = msg.HWnd, wParam = msg.WParam, lParam = msg.LParam };
}
}