将事件传播到所有控件
Propagate event to all controls
我正在使用以下代码,用于文档、错误处理 and/or 日志记录。当我按 Control+Alt+Shift 单击它时,它会保存 UserControl 或 Form 的图像:
public Image GetImage()
{
Bitmap oBmp = new Bitmap(this.Width, this.Height);
this.DrawToBitmap(oBmp, new Rectangle(0, 0, oBmp.Width, oBmp.Height));
return (Image)oBmp;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
bool bControl = false;
bool bShift = false;
bool bAlt = false;
bControl = (Control.ModifierKeys & Keys.Control) == Keys.Control;
bShift = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
bAlt = (Control.ModifierKeys & Keys.Alt) == Keys.Alt;
if (bControl && bShift && bAlt)
{
GetImage().Save(this.Name.TimedLocalFileName("png"), ImageFormat.Png);
}
}
现在,我正在以基本形式等方式在每个 UserControl 中对其进行编码。这很容易做到,因为我使用的是代码片段。但它有明显的挫折。
- 同一段代码在很多地方(可维护性);和
- 仅当我单击基本控件而不是它的子控件时才起作用(如果 UserControl 有标签,这不起作用。
我这几天一直在分析 GlobalHooks(主要是在这里:CodeProject,但我的头脑没有帮助我。
任何建议将不胜感激。
注意: TimedLocalFileName 是一种扩展方法,returns 一个格式为 <ControlName>_<Culture>_<YYYYMMDD>_<HHMMSS>.<FileExtension>
的字符串
回答问题 1
The same piece of code in a lot of places (maintainability)
它并不总是适用,但如果您发现自己经常使用此行为,您可以继承 UserControl
来创建 BitmapExportUserControl
并将 Image GetImage()
和 override void OnMouseDown(MouseEventArgs e)
放入这个 class 而不是,并使所有需要此行为的自定义控件继承自 BitmapExportUserControl
.
另一种方法可以从您的 Form
本身执行位图导出,并让您的 Form
订阅其所有子对象 Control
的所有 MouseDown
事件.
回答问题 2
Works only when I click on the base control and not it's childs
据我所知,WinForms 中没有内置的 "up" 事件传播(或冒泡),例如 WPF。一个解决方案可能是公开一个事件,当应用程序中有 MouseDown
事件时,应用程序中的所有 UserControl
都可以引发该事件。您的代码将变为:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.RaiseGlobalMouseDownEvent(this, e);
}
你会让你的主要 Form
订阅这个 GlobalMouseDown.GlobalMouseDownEvent
并执行检查和位图导出。
这在功能上等同于在某些 GlobalMouseDown
class 中有一个 public 方法 HandleMouseDown
,所有 UserControl
[=28] 都会调用该方法=].每个 UserControl
中的代码将变为:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.HandleMouseDown(this, e);
}
您将使用此方法进行检查和位图导出。
创建一个基础 UserControl
并将其命名为 BaseUserControl
并从 BaseUserControl
派生所有用户控件,然后您可以将所有逻辑放在基础用户控件中。
在BaseUserControl
内部,使用递归的方法,处理所有子控件的MouseDown
事件,重定向到OnMouseDown
of this
, like .
覆盖 OnHanldeCrated
并调用该递归方法来连接事件。
这里是基础控件:
using System;
using System.Drawing;
using System.Windows.Forms;
public class BaseUserControl : UserControl
{
void WireMouseEvents(Control container)
{
foreach (Control c in container.Controls)
{
c.MouseDown += (s, e) =>
{
var p = PointToThis((Control)s, e.Location);
OnMouseDown(new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta));
};
WireMouseEvents(c);
};
}
Point PointToThis(Control c, Point p)
{
return PointToClient(c.PointToScreen(p));
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (Control.ModifierKeys == (Keys.Control | Keys.Alt | Keys.Shift))
MessageBox.Show("Handled!");
// Your custom logic
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
WireMouseEvents(this);
}
}
我正在使用以下代码,用于文档、错误处理 and/or 日志记录。当我按 Control+Alt+Shift 单击它时,它会保存 UserControl 或 Form 的图像:
public Image GetImage()
{
Bitmap oBmp = new Bitmap(this.Width, this.Height);
this.DrawToBitmap(oBmp, new Rectangle(0, 0, oBmp.Width, oBmp.Height));
return (Image)oBmp;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
bool bControl = false;
bool bShift = false;
bool bAlt = false;
bControl = (Control.ModifierKeys & Keys.Control) == Keys.Control;
bShift = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
bAlt = (Control.ModifierKeys & Keys.Alt) == Keys.Alt;
if (bControl && bShift && bAlt)
{
GetImage().Save(this.Name.TimedLocalFileName("png"), ImageFormat.Png);
}
}
现在,我正在以基本形式等方式在每个 UserControl 中对其进行编码。这很容易做到,因为我使用的是代码片段。但它有明显的挫折。
- 同一段代码在很多地方(可维护性);和
- 仅当我单击基本控件而不是它的子控件时才起作用(如果 UserControl 有标签,这不起作用。
我这几天一直在分析 GlobalHooks(主要是在这里:CodeProject,但我的头脑没有帮助我。
任何建议将不胜感激。
注意: TimedLocalFileName 是一种扩展方法,returns 一个格式为 <ControlName>_<Culture>_<YYYYMMDD>_<HHMMSS>.<FileExtension>
回答问题 1
The same piece of code in a lot of places (maintainability)
它并不总是适用,但如果您发现自己经常使用此行为,您可以继承 UserControl
来创建 BitmapExportUserControl
并将 Image GetImage()
和 override void OnMouseDown(MouseEventArgs e)
放入这个 class 而不是,并使所有需要此行为的自定义控件继承自 BitmapExportUserControl
.
另一种方法可以从您的 Form
本身执行位图导出,并让您的 Form
订阅其所有子对象 Control
的所有 MouseDown
事件.
回答问题 2
Works only when I click on the base control and not it's childs
据我所知,WinForms 中没有内置的 "up" 事件传播(或冒泡),例如 WPF。一个解决方案可能是公开一个事件,当应用程序中有 MouseDown
事件时,应用程序中的所有 UserControl
都可以引发该事件。您的代码将变为:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.RaiseGlobalMouseDownEvent(this, e);
}
你会让你的主要 Form
订阅这个 GlobalMouseDown.GlobalMouseDownEvent
并执行检查和位图导出。
这在功能上等同于在某些 GlobalMouseDown
class 中有一个 public 方法 HandleMouseDown
,所有 UserControl
[=28] 都会调用该方法=].每个 UserControl
中的代码将变为:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.HandleMouseDown(this, e);
}
您将使用此方法进行检查和位图导出。
创建一个基础 UserControl
并将其命名为 BaseUserControl
并从 BaseUserControl
派生所有用户控件,然后您可以将所有逻辑放在基础用户控件中。
在BaseUserControl
内部,使用递归的方法,处理所有子控件的MouseDown
事件,重定向到OnMouseDown
of this
, like
覆盖 OnHanldeCrated
并调用该递归方法来连接事件。
这里是基础控件:
using System;
using System.Drawing;
using System.Windows.Forms;
public class BaseUserControl : UserControl
{
void WireMouseEvents(Control container)
{
foreach (Control c in container.Controls)
{
c.MouseDown += (s, e) =>
{
var p = PointToThis((Control)s, e.Location);
OnMouseDown(new MouseEventArgs(e.Button, e.Clicks, p.X, p.Y, e.Delta));
};
WireMouseEvents(c);
};
}
Point PointToThis(Control c, Point p)
{
return PointToClient(c.PointToScreen(p));
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (Control.ModifierKeys == (Keys.Control | Keys.Alt | Keys.Shift))
MessageBox.Show("Handled!");
// Your custom logic
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
WireMouseEvents(this);
}
}