using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SystemX.Net.Platform.Common.ExtensionMethods
{
///
/// http://lostechies.com/derickbailey/2011/01/24/asynchronous-control-updates-in-c-net-winforms/
///
public static class EmControl
{
public static void Do(this TControl control, Action action)
where TControl : Control
{
try
{
if (control.InvokeRequired)
{
try
{
control.Invoke(action, control);
}
catch (Exception ex)
{
if (ex is ObjectDisposedException)
Trace.WriteLine(ex);
else
throw;
}
}
else if (control.IsHandleCreated)
action(control);
else
{
Console.WriteLine("Error : Before windows handle created.. 창 핸들을 만들기 전까지는....");
Trace.WriteLine("Error : Before windows handle created.. 창 핸들을 만들기 전까지는....");
}
}
catch (Exception ex)
{
Trace.WriteLine($"Exception on Control.Do(): {ex}");
}
}
///
/// Control.Invoke is synchronous
///
///
///
public static void Do(this Control control, Action action)
{
try
{
if (control.InvokeRequired)
{
try
{
control.Invoke(action);
}
catch (Exception ex)
{
if (ex is ObjectDisposedException)
Trace.WriteLine(ex);
else
throw;
}
}
else if (control.IsHandleCreated)
action();
else
{
Console.WriteLine("Error : Before windows handle created (2).. 창 핸들을 만들기 전까지는....");
Trace.WriteLine("Error : Before windows handle created (2).. 창 핸들을 만들기 전까지는....");
}
}
catch (Exception ex)
{
Trace.WriteLine($"Exception on Control.Do(): {ex}");
}
}
public static void Do(this SynchronizationContext context, Action action)
{
context.Send(ignore => { action(); }, null);
}
public static void DoAsync(this SynchronizationContext context, Action action)
{
context.Post(ignore => { action(); }, null);
}
public static SynchronizationContext GetSynchronizationContext(this Control control)
{
SynchronizationContext context = null;
control.Do(() =>
{
context = SynchronizationContext.Current;
});
return context;
}
public static TaskScheduler GetTaskScheduler(this Control control)
{
TaskScheduler scheduler = null;
control.Do(() =>
{
scheduler = TaskScheduler.FromCurrentSynchronizationContext();
});
return scheduler;
}
///
/// form 에 대해서, 아직 창 핸들이 만들어 지지 않은 경우, form 이 보여진 후에 해당 action 을 수행한다.
///
///
///
public static void DoNowOrLater(this Form form, Action action)
{
if (form.InvokeRequired)
form.Invoke(action);
else if (form.IsHandleCreated)
action();
else
form.Shown += (sender, args) => { action(); };
}
public static async Task DoAsync(this Control control, Action action)
{
try
{
if (control.InvokeRequired)
await Task.Factory.FromAsync(control.BeginInvoke(action), result => { });
else if (control.IsHandleCreated)
action();
else
Console.WriteLine("Error : 창 핸들을 만들기 전까지는....");
}
catch (Exception ex)
{
Trace.WriteLine($"Exception on Control.Do(): {ex}");
}
}
///
/// How to get return value when BeginInvoke/Invoke is called in C#
/// http://stackoverflow.com/questions/2214002/how-to-get-return-value-when-begininvoke-invoke-is-called-in-c-sharp
///
public static T DoGet(this Control control, Func func)
{
if (control.InvokeRequired)
return (T)control.Invoke(func);
return func();
}
public static IEnumerable CollectAncestors(this Control control, bool includeMe = false)
{
if (includeMe)
yield return control;
if (control == null || control.Parent == null)
yield break;
foreach (var ancestor in control.Parent.CollectAncestors(true))
yield return ancestor;
}
public static IEnumerable CollectAncestorsTo(this Control control, Control stopAncestorControl,
bool includeMe = false)
{
if (includeMe)
yield return control;
if (control == stopAncestorControl || control.Parent == null)
yield break;
foreach (var ancestor in control.Parent.CollectAncestorsTo(stopAncestorControl, true))
yield return ancestor;
}
public static IEnumerable CollectChildren(this Control control, bool includeMe = false)
{
if (includeMe)
yield return control;
foreach (var child in control.Controls.Cast())
{
foreach (var descendant in child.CollectChildren(true))
yield return descendant;
}
if (control is TabControl)
{
var tab = (TabControl) control;
foreach (var page in tab.TabPages.Cast())
{
foreach (var descendant in page.CollectChildren(true))
{
yield return descendant;
}
}
}
}
public static IEnumerable CollectChildren(this Control control, bool includeMe = false) where T : Control
{
return control.CollectChildren(includeMe).OfType();
//if (includeMe && control is T)
// yield return control as T;
//foreach (var child in control.Controls.Cast())
//{
// foreach (var descendant in child.CollectChildren(true))
// yield return descendant;
//}
//if (control is TabControl)
//{
// var tab = (TabControl)control;
// foreach (var page in tab.TabPages.Cast())
// {
// foreach (var descendant in page.CollectChildren(true))
// {
// yield return descendant;
// }
// }
//}
}
///
/// reference 의 LT 좌표 기준으로, control 의 LT 좌표의 offset 값을 반환한다.
///
///
///
///
public static Point GetRelativePoint(this Control control, Control reference)
{
return reference.PointToClient(control.PointToScreen(control.Location));
}
public static Rectangle GetRelativeRectangle(this Control control, Control reference)
{
return reference.RectangleToClient(control.RectangleToScreen(control.ClientRectangle));
}
public static void SetBackgroundImage(this Control control, Image image)
{
if (control.BackgroundImage != null)
control.BackgroundImage.Dispose();
control.BackgroundImage = image;
}
public static void MakeTransparent(this Control control)
{
try
{
if (control is Button)
((Button) control).FlatStyle = FlatStyle.Flat;
control.ForceMakeTransparent();
control.BackColor = Color.Transparent;
}
catch (Exception)
{
}
}
///
/// http://solvedstack.com/questions/transparency-for-windows-forms-textbox
///
/// bool itWorked = SetStyle(xControl, ControlStyles.SupportsTransparentBackColor, true);
///
///
///
///
///
///
public static bool ForceSetStyle(this Control control, ControlStyles style, bool value)
{
Type typeTB = typeof (Control);
System.Reflection.MethodInfo misSetStyle = typeTB.GetMethod("SetStyle",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (misSetStyle != null && control != null)
{
misSetStyle.Invoke(control, new object[] {style, value});
return true;
}
return false;
}
public static bool ForceMakeTransparent(this Control control, bool transparent = true)
{
return control.ForceSetStyle(ControlStyles.SupportsTransparentBackColor, transparent);
}
///
/// http://stackoverflow.com/questions/435433/what-is-the-preferred-way-to-find-focused-control-in-winforms-app
///
///
///
public static Control FindFocusedControl(this Control control)
{
var container = control as IContainerControl;
while (container != null)
{
control = container.ActiveControl;
container = control as IContainerControl;
}
return control;
}
// http://stackoverflow.com/questions/4747935/c-sharp-winform-check-if-control-is-physicaly-visible
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y) { X = x; Y = y; }
public static implicit operator Point(POINT p) => new Point(p.X, p.Y);
public static implicit operator POINT(Point p) => new POINT(p.X, p.Y);
}
/// control 이 실제로 사용자에게 보이는지 여부를 반환
public static bool IsControlVisibleToUser(this Control control)
{
return control.DoGet(() =>
{
if (!control.IsHandleCreated)
return false;
var pos = control.PointToScreen(control.Location);
var pointsToCheck = new POINT[] {
pos,
new Point(pos.X + control.Width - 1, pos.Y),
new Point(pos.X, pos.Y + control.Height - 1),
new Point(pos.X + control.Width - 1, pos.Y + control.Height - 1),
new Point(pos.X + control.Width/2, pos.Y + control.Height/2),
};
foreach (var p in pointsToCheck)
{
var hwnd = WindowFromPoint(p);
var other = Control.FromChildHandle(hwnd);
if (other == null)
continue;
if (control == other || control.Contains(other))
return true;
}
return false;
});
}
#region Detect cursor
//// http://stackoverflow.com/questions/586479/is-there-a-quick-way-to-get-the-control-thats-under-the-mouse
//[DllImport("user32.dll")]
//private static extern IntPtr WindowFromPoint(Point pnt);
//public static Control ControlUnderPoint(this Point pt)
//{
// IntPtr hWnd = WindowFromPoint(pt);
// if (hWnd != IntPtr.Zero)
// return Control.FromHandle(hWnd);
// return null;
//}
//public static Control ControlUnderMouseCursor()
//{
// return Control.MousePosition.ControlUnderPoint();
//}
/// Checks whether mouse is over given control
public static bool IsMouseOver(this Control control)
{
return control.ClientRectangle.Contains(control.PointToClient(Cursor.Position));
}
/// Collects controls under mouse cursor
public static IEnumerable GetChildrenUnderMouse(this Control parent)
{
foreach (var c in parent.Controls.Cast())
{
if (c.IsMouseOver())
yield return c;
foreach (var cc in GetChildrenUnderMouse(c))
yield return cc;
}
}
#endregion
/// Button 에 image 를 입힌다. text 는 왼쪽, image 는 오른쪽
public static void AddImage(this Button button, Image image)
{
button.Image = image;
button.ImageAlign = ContentAlignment.MiddleRight;
button.TextAlign = ContentAlignment.MiddleLeft;
}
}
}