2023-09-29 13:58:35 -04:00
using System.Linq ;
using System.Windows.Forms ;
2019-08-27 18:03:21 -04:00
using static Vanara . PInvoke . User32 ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
namespace Vanara.Extensions ;
/// <summary>Control extension methods.</summary>
public static partial class ControlExtension
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
/// <summary>
/// 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.
/// </summary>
/// <param name="ctrl">This control.</param>
/// <param name="action">The action to execute.</param>
public static void CallWhenHandleValid ( this Control ctrl , Action < Control > action )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( ctrl . IsHandleCreated )
{
action ( ctrl ) ;
}
else if ( ! ctrl . IsDesignMode ( ) )
2017-11-27 13:11:20 -05:00
{
2023-09-29 13:58:35 -04:00
void handler ( object? sender , EventArgs e )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
if ( ! ctrl . IsHandleCreated ) return ;
ctrl . HandleCreated - = handler ;
2017-11-27 13:11:20 -05:00
action ( ctrl ) ;
}
2018-05-13 23:40:14 -04:00
2023-03-31 11:47:53 -04:00
ctrl . HandleCreated + = handler ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Enables all children of a control.</summary>
/// <param name="ctl">This control.</param>
/// <param name="enabled">If set to <c>true</c> enable all children, otherwise disable all children.</param>
public static void EnableChildren ( this Control ctl , bool enabled )
{
2023-09-29 13:58:35 -04:00
foreach ( Control sub in ctl . Controls . Cast < Control > ( ) )
2017-11-27 13:11:20 -05:00
{
2023-09-29 13:58:35 -04:00
if ( sub is ButtonBase or ListControl or TextBoxBase )
2023-03-31 11:47:53 -04:00
sub . Enabled = enabled ;
sub . EnableChildren ( enabled ) ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the control in the list of parents of type <c>T</c>.</summary>
/// <typeparam name="T">The <see cref="Control"/> based <see cref="Type"/> of the parent control to retrieve.</typeparam>
/// <param name="ctrl">This control.</param>
/// <returns>The parent control matching T or null if not found.</returns>
2023-09-29 13:58:35 -04:00
public static T ? GetParent < T > ( this Control ctrl ) where T : class
2023-03-31 11:47:53 -04:00
{
var p = ctrl . Parent ;
2023-09-29 13:58:35 -04:00
while ( p is not null and not T )
2023-03-31 11:47:53 -04:00
p = p . Parent ;
return p as T ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the top-most control in the list of parents of type <c>T</c>.</summary>
/// <typeparam name="T">The <see cref="Control"/> based <see cref="Type"/> of the parent control to retrieve.</typeparam>
/// <param name="ctrl">This control.</param>
/// <returns>The top-most parent control matching T or null if not found.</returns>
2023-09-29 13:58:35 -04:00
public static T ? GetTopMostParent < T > ( this Control ctrl ) where T : class
2023-03-31 11:47:53 -04:00
{
var stack = new System . Collections . Generic . Stack < Control > ( ) ;
var p = ctrl . Parent ;
while ( p ! = null )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
stack . Push ( p ) ;
p = p . Parent ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
while ( stack . Count > 0 )
if ( ( p = stack . Pop ( ) ) is T )
return p as T ;
return null ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the right to left property.</summary>
/// <param name="ctrl">This control.</param>
/// <returns>Culture defined direction of text for this control.</returns>
public static RightToLeft GetRightToLeftProperty ( this Control ctrl )
{
2023-12-30 19:50:35 -05:00
Control ? c = ctrl ;
while ( c ! = null )
2017-11-27 13:11:20 -05:00
{
2023-12-30 19:50:35 -05:00
if ( c . RightToLeft ! = RightToLeft . Inherit )
return c . RightToLeft ;
c = c . Parent ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
return RightToLeft . No ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Determines whether this control is in design mode.</summary>
/// <param name="ctrl">This control.</param>
/// <returns><c>true</c> if in design mode; otherwise, <c>false</c>.</returns>
public static bool IsDesignMode ( this Control ctrl )
{
var p = ctrl ;
while ( p ! = null )
2017-11-27 13:11:20 -05:00
{
2023-03-31 11:47:53 -04:00
var site = p . Site ;
if ( site ! = null & & site . DesignMode )
return true ;
p = p . Parent ;
2017-11-27 13:11:20 -05:00
}
2023-03-31 11:47:53 -04:00
return false ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Gets a string using a message pattern that asks for the string length by sending a GetXXXLen message and then a GetXXXText message.
/// </summary>
/// <param name="ctrl">The control.</param>
/// <param name="getLenMsg">The window message identifier for retrieving the string length.</param>
/// <param name="getTextMsg">The window message identifier for retrieving the string.</param>
/// <returns>The string result from the message call.</returns>
2023-09-29 13:58:35 -04:00
public static string? GetMessageString ( this Control ctrl , uint getLenMsg , uint getTextMsg )
2023-03-31 11:47:53 -04:00
{
if ( ! ctrl . IsHandleCreated ) return null ;
var cp = ctrl . SendMessage ( getLenMsg ) . ToInt32 ( ) + 1 ;
2023-09-29 13:58:35 -04:00
var sb = new StringBuilder ( cp ) ;
2023-08-04 12:24:49 -04:00
PInvoke . User32 . SendMessage ( ctrl . Handle , getTextMsg , ref cp , sb ) ;
2023-03-31 11:47:53 -04:00
return sb . ToString ( ) ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Retrieves the window styles.</summary>
/// <param name="ctrl">The control.</param>
/// <returns>The window styles</returns>
public static int GetStyle ( this Control ctrl ) = > GetWindowLongAuto ( ctrl . Handle , WindowLongFlags . GWL_STYLE ) . ToInt32 ( ) ;
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Removes the mnemonic, if one exists, from the string.</summary>
/// <param name="str">The string.</param>
/// <returns>A mnemonic free string.</returns>
2023-09-29 13:58:35 -04:00
public static string? RemoveMnemonic ( this string? str )
2023-03-31 11:47:53 -04:00
{
2023-09-29 13:58:35 -04:00
if ( string . IsNullOrEmpty ( str ) ) return str ;
for ( int i = 0 ; i < str ! . Length ; i + + )
if ( str [ i ] = = '&' )
if ( i < str . Length - 1 & & str [ i + 1 ] = = '&' )
i + + ;
else
return str . Remove ( i , 1 ) ;
2023-03-31 11:47:53 -04:00
return str ;
}
2017-11-27 13:11:20 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// <para>
/// Sends the specified message to a window or windows. The <c>SendMessage</c> function calls the window procedure for the specified window and does not
/// return until the window procedure has processed the message.
/// </para>
/// <para>
/// To send a message and return immediately, use the <c>SendMessageCallback</c> or <c>SendNotifyMessage</c> function. To post a message to a thread's
/// message queue and return immediately, use the <c>PostMessage</c> or <c>PostThreadMessage</c> function.
/// </para>
/// </summary>
/// <param name="wnd">
/// <para>
/// A window whose window procedure will receive the message.
/// </para>
/// <para>
/// 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.
/// </para>
/// </param>
/// <param name="msg">The message to be sent.</param>
/// <param name="wParam">Additional message-specific information.</param>
/// <param name="lParam">Additional message-specific information.</param>
/// <returns>The return value specifies the result of the message processing; it depends on the message sent.</returns>
public static IntPtr SendMessage ( this IWin32Window wnd , uint msg , IntPtr wParam = default , IntPtr lParam = default ) = >
wnd . Handle ! = IntPtr . Zero & & wnd . Handle . ToInt32 ( ) ! = - 1
2023-08-04 12:24:49 -04:00
? PInvoke . User32 . SendMessage ( wnd . Handle , msg , wParam , lParam )
2023-03-31 11:47:53 -04:00
: IntPtr . Zero ;
2018-05-31 16:39:11 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Sets the windows styles.</summary>
/// <param name="ctrl">The control.</param>
/// <param name="style">The style flags.</param>
/// <param name="on">if set to <c>true</c> add the style, otherwise remove it.</param>
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 ( ) ;
}
2019-01-08 10:17:19 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Converts a <see cref="PInvoke.MSG"/> structure to a <see cref="Message"/> structure.</summary>
/// <param name="msg">The MSG instance.</param>
/// <returns>An equivalent <see cref="Message"/> structure.</returns>
public static Message ToMessage ( this PInvoke . MSG msg ) = > Message . Create ( ( IntPtr ) msg . hwnd , ( int ) msg . message , msg . wParam , msg . lParam ) ;
2019-01-08 10:17:19 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Converts a <see cref="Message"/> structure to a <see cref="PInvoke.MSG"/> structure.</summary>
/// <param name="msg">The Message instance.</param>
/// <returns>An equivalent <see cref="PInvoke.MSG"/> structure.</returns>
2023-09-24 17:26:46 -04:00
public static PInvoke . MSG ToMSG ( this Message msg ) = > new ( ) { message = ( uint ) msg . Msg , hwnd = msg . HWnd , wParam = msg . WParam , lParam = msg . LParam } ;
2019-01-08 10:17:19 -05:00
}