Is there an event for panel that is equivalent to form event Shown?
I had a few couple of panel switching within a form which will never be closed.
However i couldn't find anything close to an event like Shown which is used in form.
The closes i had is Paint event. However i only wish to update the panel once every time it is shown.
Form.Shown is not raised every time the form is shown, rather it Occurs whenever the form is first displayed. This being said, there is no Panel.Shown event, and no event which is raised "whenever a panel is first displayed".
You can simulate this behavior with the Panel.Paint event, using a flag to keep track of whether it's been "shown" once before. This will make it behave similar to Form.Shown.
private bool panel1Painted = false;
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (!panel1Painted)
{
// do your shown stuff here
panel1Painted = true;
}
}
To keep in the spirit of Form.Shown, you may want to reset the flag if the Panel is reconstructed. This is not the same as shown.
You could listen on the VisibleChanged event and only act on when visibility = true.
https://msdn.microsoft.com/en-us/library/system.windows.forms.panel_events%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
You could also experiment with the Enter and Invalidated events to see if these give you the results you want.
Or if disabling the panel when leaving it is an option, you might be able to use the EnabledChanged event in your toolbox.
Related
I have a form with only a ReportViewer control on it. When the form is displayed, if you click on the report you can then use the mouse wheel to scroll vertically.
I'd like to be able to scroll as soon as the form appears.
I've tried the following, but no dice...
private void ReportViewer_Load(object sender, EventArgs e)
{
rptViewer.Focus();
}
private void ReportViewer_Activated(object sender, EventArgs e)
{
rptViewer.Focus();
}
Put your code in the form's constructor, right after InitializeComponent();:
rptViewer.Select();
After set rptViewer.Focus call SendKeys.Send(Chr(Keys.Tab)) to move focus from menu to preview area.
Did you try calling rptView.Activate()?
Also it may be that your form is getting focus after the load event completes (I think I've had problems with that before). One solution is, although it is definitely not elegant, to create a single-use Timer that starts when your Load method runs, and fires after 1 ms, and then stops. When the Timer fires, it will activate/focus your ReportViewer.
You could also try adding a MouseWheel event handler to your form. When the event is fired, send a scroll message to your ReportViewer to scroll it up or down. Then it doesn't matter whether or not your ReportViewer has focus, it (should) always scroll when the form has focus.
Here's my setup: I have a TabControl with numerous tabs, and on the last tab, I have a UserControl that is added to a TabPage. This UserControl has a VisibleChanged event that is supposed to check if it is visible, and if it is displays certain information using CustomCommand().
void MyUserControl_VisibleChanged(object sender, EventArgs e)
{
//MessageBox.Show("");
UserControl us = sender as UserControl;
if (us.Visible)
{
CustomCommand();
}
//MessageBox.Show("");
}
Here is the problem: this code as-is will incorrectly think the UserControl is visible when it is not, and the CustomCommand() will run when it's not supposed to. When the commented-out MessageBox function is un-commented in either spot, the UserControl is correctly seen as not visible until, of course, the TabPage is selected. Does anyone have any idea why this would be?
Just putting it on a TabPage doesn't explain this problem. There must be other layout events involved that make the control actually visible later. The MessageBox.Show() call provides the time machine to get the Visible property checked with a delay.
The standard technique to get code to run later, the way MessageBox does, is by using the Control.BeginInvoke() method. The delegate target runs when all events have been fired and processed and the UI thread goes idle again. Like this:
void MyUserControl_VisibleChanged(object sender, EventArgs e)
{
UserControl us = sender as UserControl;
this.BeginInvoke(new Action(() => {
if (us.Visible)
{
CustomCommand();
}
});
}
Not sure if this will help you, but there is a strange, and afaik undocumented, asymmetrical behaviour with the Visible_Changed event:
It does get raised whenever the Visible property of the control changes, either to true or to false.
It also get raised whenever the Parent's Visible property changes to true and only to true!
I could not raise the event by hiding the Control by another control, or for that matter by the MessageBox, though.
I don't know how your application works, so I could not reproduce. But I did notice that indeed, when changing tabs the Visible_Changed event of a Control on the TabPage does get raised, whenever the page is selected (but not when it is unselected.) I didn't know either.
You can try to catch the other direction by either going for the SelectionIndexChanged or by hooking into the VisibleChanged event of the TabPage. This is not visible in the IDE, but it does work both ways:
tabPagexyz2.VisibleChanged += tabPagexyz_VisibleChanged;
void tabPage2_VisibleChanged(object sender, EventArgs e)
{
// do something
}
I saw wild guesses about UI race conditions being behind it, which I doubt. This would at least explain why a MessageBox would habe an influence. If you want to test, you could replace it with one the evil Applictaion.DoEvents.
How to capture mouse wheel on panel in C#?
I'm using WinForms
EDIT:
I try to do it on PictureBox now.
My code:
this.pictureBox1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseClick);
this.pictureBox1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseClick);
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
MessageBox.Show("Click");
}
Clicking works. Wheelling doesn't.
Why?
If you can't see the "MouseWheel" event on a component, then you need to create it manually. Also, we need to focus that component, otherwise the "MouseWheel" event will not work for that component. I will show you how to create a "MouseWheel" event for "pictureBox1" and how it works.
INSIDE THE CONSTRUCTOR, create a mousewheel event on that component.
InitializeComponent();
this.pictureBox1.MouseWheel += pictureBox1_MouseWheel;
CREATE THE FUNCTION manually. According to my example, call it "pictureBox1_MouseWheel"
private void pictureBox1_MouseWheel(object sender, MouseEventArgs e)
{
//you can do anything here
}
CREATE a MouseHover event on that component (Go to properties in PicureBox1, select event, locate "MouseHover" and double-click the "MouseHover" event).
CALL "Focus()"; method inside that MouseHover event.
pictureBox1.Focus();
Now run the program.
Windows sends the WM_MOUSEWHEEL message to the control that has the focus. That won't be Panel, it is not a control that can get the focus. As soon as you put a control on the panel, say a button, then the button gets the focus and the message.
The button however has no use for the message, it's got nothing to scroll. Windows notices this and sends the message to the parent. That's the panel, now it will scroll.
You'll find code for a custom panel that can get the focus in this answer.
UPDATE: note that this behavior has changed in Windows 10. The new "Scroll inactive windows when I hover over them" option is turned on by default. The makes the mouse wheel behavior more consistent with the way it works in a browser or, say, an Office program. In this specific case the picturebox now will get the event. Watch out for this.
To wire it up manually...
this.panel1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);
private void panel1_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
{
///process mouse event
}
Easier method is in visual studio click on panel, goto properties viewpanel, select events, locate and double click the "mousewheel" event.
In Winforms, this is achieved using the Control.MouseWheel event
Getting mousewheel events is tricky. The easiest way is using
this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);
instead of
this.panel1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);
This way the form gets the event instead of control. This way is easy but has one problem: you can use only one mousewheel event in your form.
If you have more than one control to get mousewheel event the best way is This answer by "Shehan Silva - weltZ"
I have this simple code, where when the user leaves the TextBox control, TreeView gets focused:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.treeView1.Nodes.Add("A");
this.treeView1.Nodes[0].Nodes.Add("A.A");
this.treeView1.Nodes.Add("B");
this.treeView1.Nodes[0].Nodes.Add("B.A");
}
private void textBox1_Leave(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Leave..");
this.treeView1.Focus();
}
}
If we execute this code the Leave event is fired twice:
Leave..
Leave..
But if we set focus to other control, only one Leave event is fired.
Is that a problem of the TreeView? Do you know any workaround? Should we report this to Microsoft?
Thanks,
RG
this.treeView1.Focus();
Do not use the Focus() method in an event handler that's called because of a focusing event, like Leave. If you need to prevent a focus change then use the Validating event instead. Setting e.Cancel = true stops it.
But do note that this isn't very logical to do so for a TreeView, there isn't anything the user can do to alter the state of the control. You'll trap the user. Maybe that was the intention, do make sure the user can still close the window. If not then you might need the FormClosing event to force e.Cancel back to false.
Given that there is no code there to wire up the event I'm guessing you did it from the designer which means a line of code such as
textBox1.Leave += new EventHandler(textBox1_Leave);
will have been added to the Form1.designer.cs, check this file to ensure the line doesn't exist more than once as for each time this line is run you will get an event trigger, so if you run the line 3 times the Leave event will fire 3 times when you leave the textbox!
HTH
OneShot
using c# winforms vs2008
I've got a textbox on a form with a method being called from the textBox1_Leave event. The method takes the contents of the textbox in question and populates other textboxes based on the contents.
My problem is that is the user has focus on the text box then clicks the button to close the form (calling this.close) then the form does not close because the textbox leave event gets fired.
If the textbox does not have focus on form close then the form closes fine.
If however a user closes the form by clicking the little X close icon in the top corner the it closes fine all the time with out the textbox leave event being fired.
How can I duplicate the X close functionality so that I can always close the form without the textbox leave event being fired?
The simplest solution is going to be to check which control is actually focused before doing your post-processing - but you can't do it in the Leave handler, because the focus will still be on the text box at that point.
Instead, you need to move your logic to the LostFocus event, which is not in the designer. You'll have to wire it up at runtime:
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.LostFocus += new EventHandler(textBox1_LostFocus);
}
private void textBox1_LostFocus(object sender, EventArgs e)
{
if (closeButton.Focused)
return;
// Update the other text boxes here
}
}
The LostFocus event happens to fire after the new control receives focus.
Clarification - you might find that it works by putting this logic in the Leave event - if the focus is changed by the mouse. If the keyboard is used instead, you'll get the wrong behaviour. LostFocus is reliable in both cases - the focused control will always be the "new" control. This is documented on MSDN: Order of Events in Windows Forms.
Incidentally, the reason why you're not having this problem with the "red X" is that the X is not actually a control that can receive focus, it's part of the window. When the user clicks that, it's not causing the text box to lose focus, and therefore isn't causing the Leave event to fire.
Another approach:
Use the textbox's validating event instead of it's leave event, then change the button's CausesValidation property to false. You will also have to set the textbox to not cause validation in the button's click event so the validating event will not fire when the form is closing (thanks to #Powerlord for pointing this out).
private void button1_Click(object sender, EventArgs e)
{
this.textBox1.CausesValidation = false;
this.Close();
}
You could also handle the FormClosing event and make sure the e.Cancel argument does not get set to true by the validating events on the other controls on the form. I think they will be fired off before the FormClosing event.
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = false;
return;
}
}
you can check to see which control has just got focus.
private void textBox1_Leave(object sender, EventArgs e)
{
if (btnClose.Focused)
return;
// go from here
}
Just check if the form owning the textbox is disposing? If it's getting closed, it's disposing. If it's disposing you could simply end the pesky 'leave' event without doing anything. I didn't check it and forgive me, I'm choked on a project of my own so and I was searching myself, so I don't think I'll have time for that.
private void GuiltyTextBox_Leave(object sender, EventArgs e) {
Form formOwningTheTextBox=(Form)((Control)sender).TopLevelControl;
if (formOwningTheTextBox.Disposing || formOwningTheTextBox.IsDisposed) return;
.......
}
I just believe this is going to work with minimum effort and wanted to send a quick answer before I resume searching my own answer.
Write Following line of code in text box leave event on top
if me.closing then
return
end if