Reputation: 337
I'm using the following piece of code, for documentation, error handling and/or logging. It's saves an image of the UserControl or Form when I click it pressing Control+Alt+Shift:
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);
}
}
Right now, I'm coding it in every UserControl, in the base form and so. It's easy to do because I'm using a code Snippet. But it has obvious setbacks.
I've been for a few days analyzing GlobalHooks (mostly here: CodeProject, but my head is not helping me.
Any suggestion will be very much appreciated.
Note: TimedLocalFileName is an extension method that returns a String in format <ControlName>_<Culture>_<YYYYMMDD>_<HHMMSS>.<FileExtension>
Upvotes: 1
Views: 575
Reputation: 125207
Create a base UserControl
and name it BaseUserControl
and derive all your user control from BaseUserControl
then you can put all the logic inside the base user control.
Inside the BaseUserControl
, using a recursive method, handle MouseDown
event of all child controls and redirect them to OnMouseDown
of this
, like this post.
Override OnHanldeCrated
and call that recursive method to wire up events.
Here is the base control:
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);
}
}
Upvotes: 3
Reputation: 4943
Answering issue 1
The same piece of code in a lot of places (maintainability)
It's not always applicable but if you find yourself using this behavior a lot, you could inherit from UserControl
to create BitmapExportUserControl
and put Image GetImage()
and override void OnMouseDown(MouseEventArgs e)
in this class instead, and make all your custom controls that need this behavior inherit from BitmapExportUserControl
.
Another way could to perform the bitmap export from your Form
itself, and have your Form
subscribe to all the MouseDown
events of all its children Control
objects.
Answering issue 2
Works only when I click on the base control and not it's childs
As far as I know, there is no built-in "up" event propagation (or bubbling) in WinForms as there is in WPF for example. A solution could be to expose an event that can be raised by all UserControl
in your application when there is a MouseDown
event on them. Your code would become:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.RaiseGlobalMouseDownEvent(this, e);
}
and you would have your main Form
subscribe to this GlobalMouseDown.GlobalMouseDownEvent
and perform the checks and bitmap export.
This is functionally equivalent to having a public method HandleMouseDown
in some GlobalMouseDown
class that would be called by all your UserControl
MouseDownEventHandlers
. The code in each UserControl
would become:
protected override void OnMouseDown(MouseEventArgs e)
{
GlobalMouseDown.HandleMouseDown(this, e);
}
and you would do your checks and bitmap export in this method.
Upvotes: 1