可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Possible Duplicate:
“ResizeEnd” equivalent for usercontrols
I feel stupid, but I can't find a solution to a problem that I think it's easy.
I have a user control that (basically) shows an image drawing it during onPaint stage:
protected override void OnPaint(PaintEventArgs e)
{
if (img != null)
e.Graphics.DrawImage(img, ...);
}
When user control is resized, it must perform many actions and one is (given a particular condition) resize image to fit width or height, etc...
Image showed can be "heavy", so when user start resizing and moves mouse, the result is a sort of slow movement that's not good for end user.
So I'm wondering if there are windows messages reporting me that the resize operation is starting or completed: if so I can stop redrawing when resize starts and repaint image when resize ends.
Thanks to everybody
EDITED:
I tried this:
protected override void WndProc(ref Message m)
{
const int WM_ENTERSIZEMOVE = 0x0231;
const int WM_EXITSIZEMOVE = 0x0232;
switch (m.Msg)
{
case WM_ENTERSIZEMOVE: resizing = true; break;
case WM_EXITSIZEMOVE: resizing = false; break;
}
}
but those messages are never called :(
回答1:
You might be interested by the Form.ResizeBegin and Form.ResizeEnd events.
If you're using WPF, this thread on MSDN might interest you. WPF requires hackery to know when the resize begins/ends
EDIT
Didn't noticed it was an UserControl ! This question seems to address your problem:
"ResizeEnd" equivalent for usercontrols
回答2:
In the Load event of your UserControl, hook event handlers to the control's form's events.
Apologies, I have a VB project open, I'll convert it in the answer when I get a moment.
Private Sub UserControl1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
AddHandler Me.FindForm.ResizeBegin, AddressOf MyFormsResizeBegin
AddHandler Me.FindForm.ResizeEnd, AddressOf MyFormsResizeEnd
End Sub
Private Sub MyFormsResizeBegin(sender As Object, e As EventArgs)
'tell your control to wait.
End Sub
Private Sub MyFormsResizeEnd(sender As Object, e As EventArgs)
'say everything is ok to continue
End Sub
回答3:
You really want to do that (windows messages)? :D
First, you cant do that like overriding PreProcessMessage
or WndProc
because I'm guessing the containing form will trap the resizing start/end message (or any other messages) so your control will not get any. The way to do that is to implement IMessageFilter
interface on your control. Then you will get this method in your control in which you can switch through the received message m:
public bool PreFilterMessage(ref Message m)
Then at the control constructor add: Application.AddMessageFilter(this);
and there you go, now Application thread is calling PreFilterMessage
method and passing it the received message.
Another idea:
If you let the users change the controls size with their mouse, you can trap MouseDown and set bool MouseIsDown
flag Then in OnResize
you can check
if(MouseIsDown && Resizing == false)
{
Resizing = true;
//Start Resizing only once
}
And on MouseUp:
if(Resizing == true && MouseIsDown == true)
{
Resizing = MouseIsDown = false;
//End the resizing once
}
回答4:
I post an answer after a long investigation.
First of all I want to thank everybody for your contribution, because your suggestions led me to the right way. Thanks to @Hans Passant too, because his solution on this post is an important piece.
THE PROBLEM:
- assume we have a usercontrol named innCnt (inner control) contained in another usercontrol named outCnt (outer control), which in turn should be placed in a form we don't develop (so we can't edit its source)
- assume we have to catch the
EndResize
event in innCnt
CONTRIBUTES:
- Using
PreProcessMessage
or overriding WndProc
(thanks to @Cipi):
I tried these solutions, but I don't receive WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages from Windows
- Trap
MouseDown
and OnResize
events (thanks to @Cipi):
It could be ok, but that logic should be moved on outCnt because innCnt could not receive MouseDown if user is resizing out control or form.
Anyway I don't like too much this solution
- In the
Load
event of innCnt, hook event handlers to the control's form's events (thanks to @hometoast and @pikzen):
I tried this solution (and the one provided by @Hans here) but this doesn't work because when innCnt is loaded, even in if not in DesignMode
, his parent is a part of outCnt, whose parent is null because not ready set!!
SOLUTION:
Basicly I had to move @Hans logic inside outCnt but not in Load
event, because even here parent is still null!
public class OuterControl
{
protected override void OnParentChanged(EventArgs e)
{
if (!this.DesignMode)
{
Form form = this.FindForm();
if (form != null)
{
form.ResizeBegin += (s, ea) =>innerCnt.Resizing = true;
form.ResizeEnd += (s, ea) => innerCnt.Resizing = false;
}
}
base.OnParentChanged(e);
}
}
public class InnerControl
{
private bool resizing = false;
public bool Resizing {
get { return resizing; };
set {
resizing = value;
if (!resizing) {
// Resizing is just finished:
// let's do what we need
}
}
}
protected override void OnResize(EventArgs e)
{
if (Resizing)
{
base.OnResize(e);
return;
}
else
{
// Perform resizing actions
}
}
}
KNOWN PROBLEMS:
I'm quite sure that if outCnt is placed inside another usercontrol, solution provided won't work...