This question already has answers here:
How to ensure that async method finished work?
(2 answers)
Closed 8 years ago.
I handle user click on a button like:
private void btnScanDirectory_Click(object sender, EventArgs e)
{
// some code
}
What events are fired after btnScanDirectory_Click() finishes it's work ?
The reason I'm asking, that in btnScanDirectory_Click() I create a new Thread() in which I "fire and forget" tree.BeginInvoke() method that updates a TreeView.
So even when worker thread closes, the main thread is still handling those multiple BeginInvoke() calls, and when I access tree like
tree.ExpandAll();
in the same btnScanDirectory_Click() - it has no effect.
I couldn't find a way to "wait in main thread while all EndInvoke() methods are called", so I want to try tree.ExpandAll() in the event that fires after btnScanDirectory_Click() is finished.
Check out this page. It has the following details and I think this is what you're asking for: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mouseclick.aspx
Depressing a mouse button when the cursor is over a control typically raises the following series of events from the control:
MouseDown event.
Click event.
MouseClick event.
MouseUp event.
Related
This question already has an answer here:
Is there any event that fires when WPF animation ends?
(1 answer)
Closed 9 years ago.
Is there a possibility to register a function to a Animated Usercontroll that is called when the animation is over?
I have a Usercontroll-Animation I start by calling .BeginAnimation(propdp, animation);
How to call another function when the Animation is over?
There is a Timeline.Completed Event that you can use. You can either set it in XAML, or in C# on a Storyboard instance. The linked page has a full working example that you can view.
The handler used is the default EventHandler delegate:
private void StoryboardCompleted(object sender, EventArgs e)
{
// the Storyboard has stopped
}
UPDATE >>>
Although the Completed event can be set on a Storyboard instance, it is in fact defined in the Timeline class. As Timeline is the base class for all AnimationTimeline classes, this means that you can also attach a handler to the Completed event from the AnimationTimeline object that you are passing into the BeginAnimation event.
There is an animation.Completed event.
I'm using the MouseLeave event to check if the user left my form and to close my window, but using
this.MouseLeave += new System.EventHandler(this.InvisibleForm_Leave);
is too slow, only if I'm going to leave my form slowly the event is fired, moving it in a normal way / a little bit faster I don't get a leave event.
Therefore I tried to check on my own if the mouse left my form or not:
private void checkPos()
{
Rectangle rec = this.Bounds;
while (true)
{
Point point = new Point(Cursor.Position.X, Cursor.Position.Y);
if (!rec.Contains(point))
{
Console.WriteLine("leaving");
this.Close();
}
Thread.Sleep(100);
}
}
started in a own thread after creating the form:
public MyForm()
{
InitializeComponent();
Thread m_mouseListenerThread = new Thread(new ThreadStart(this.checkPos));
m_mouseListenerThread.Start();
}
But with this I have more or less the same problem, leaving the area still returns true after checking it with rec.Contains(point) only after a second he is going to execute the if code, but sometimes he's getting it in an instant.
The second problem with this is that I'm getting a thread exception in the this.Close(); line in the checkPost() method:
Cross-thread operation not valid: Control 'MyForm' accessed from a thread other than the thread it was created on.
Now I don't really know how to implement the mouse leaving part in another way.
I don't think MouseLeave performance is the issue here. I've used the MouseLeave (in combination with MouseEnter and MouseMove) to automatically fade in/out forms. It works :).
Here's a sample form with just a Label:
If MouseLeave is handled for both the Label and the Form, the event handler always fires regardless of how fast I move the mouse. For example:
this.label1.MouseLeave += new System.EventHandler(this.HandleMouseLeave);
this.MouseLeave += new System.EventHandler(this.HandleMouseLeave);
private void HandleMouseLeave(object sender, EventArgs e)
{
Debug.WriteLine(string.Format("MouseLeave: {0}", DateTime.Now));
}
However, if I remove the MouseLeave handler for label1, I am able to reproduce the behavior that you are seeing. If I move the mouse slowly from label1 (orange) to the form (green) and outside, the event fires. If I move the mouse quickly from label1 to outside of the form, the event does not fire.
So, what I think is happening is that a child control of your form is firing a MouseLeave event, and you are not handling that event. The reason you see the event fire when you move the mouse slowly is because you are hovering over the form area long enough to produce the event.
Further, spawning a separate thread to monitor MouseLeave events is not a good approach. Your performance will suffer as this thread polls for an event state (as opposed to waiting for an event), you are creating an unnecessary headache of starting/stopping the threads, and you will need to invoke back onto the UI thread whenever you want to do anything with the form (as you have learned). If you have the time to revisit the MouseLeave event approach, I would highly recommend that you do so. Good luck!
For the mouse leaving part, I am not quite sure. Maybe you can try to handle that by MouseMove event?
For the invalid cross-thread operation issue, you simply cannot access a control which is owned by another thread (it's the UI thread in your case). Use Control.BeginInvoke or Control.Invoke instead.
I faced same problem, do that:
put timer in form.
Put your code in timer tick event like mouse leave:
Label1.BackColor=Color.PaleGreen;
Set timer interval to less than 30
Use this function
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
timer1_Tick(label1(example), e);
}
Put this in formload event
timer1.Tick += timer1_Tick;
the code will run very quickly and easy , you will never see any problem like this again
I have a form that appears as shown in the attached image. I have two parts of the form that concern this question: the TabControl, and the Panel, as shown in the image. It should be noted that the panel is NOT within the TabControl.
My situation is that I have a thread that executes continuously when the button, displayed in melt-your-eyes green in the Panel, is clicked. The thread polls the device which I'm interfacing with and updates the controls in the "Status" GroupBox at the bottom of the TabControl. When the user clicks on a control in the TabControl (tabControl_Enter event), I trigger a ManualResetEvent which lets the thread finish its iteration so that I can perform the IO required by the clicked control. The code to to suspend the thread is as follows:
private void StopSynchThread()
{
synchWaitHandle.Reset();
//various UI changes
}
private void updateSynchStat()
{
while (true)
{
synchWaitHandle.WaitOne();
try
{
updateSynch();
}
}
What I would like to do is then restart the thread automatically, instead of by button press, as is currently done. What I'm trying to do is avoid having to restart the thread by conditionally calling StartSynchThread() within each of the "bazillion" UI event handlers. StartSynchThread() is defined as:
private void StartSynchThread()
{
synchWaitHandle.Set();
}
Is there a precedent or decent paradigm for handling this? Without any concept of how to do so, I was thinking that I could alter my function that performs the IO with the device to generate an event after it gets a response from the device, but that seems inelegant.
Any ideas? I appreciate your insights. Thanks.
If you really can fire it off with a simple button click, you ought to be able to just put a timer on the form that will periodically check for the right conditions and then "push" the button (call synchWaitHandle.Set();) automatically.
Imagine the following scenario:
this.SetStyle(ControlStyles.UserPaint, true); //this doesn’t change anything
…
void OpenSomeForm()
{
SomeForm sf = new SomeForm();
sf.SomeEvent += new … (SomeEventOcurred);
sf.ShowDialog();
}
private void SomeEventOcurred(…)
{
OnePanelInThisForm.Invalidate();
}
private void OnePanelInThisForm_Paint(object sender, PaintEventArgs e)
{
DoSomeDrawing(e.Graphics);
}
Now, OnePanelInThisForm draws correctly when the form loads. But if SomeEventOcurred is Fired from “SomeForm”, the paint event is not fired. If I close and reopen the form it correctly repaints.
If I add a button to the form that executes: OnePanelInThisForm.Invalidate(); the panel is correctly repaint.
What am I missing?
UPDATE: Clarification. (why don’t we do this in the first place…)
I have a FORM_A. This FORM_A has a Panel that overrides the Paint event. It’s a standard WinForm. In the Paint it draws a circle. This works. Turns out that FORM_A has a button that opens FORM_B. But before doing that, it subscribes to a custom event in FORM_B called: SomeEvent. (see the sample above). So FORM_B can tell FORM_A about “SomeEvent”.
Now, FORM_B is also a normal WinForm. And it has a normal Button. In the Click event of that button, it opens FORM_C. FORM_C also has an event called SomeEvent and obviously FORM_B subscribes to that event. Exactly like before. The idea is that FORM_C has a button that will trigger that event, notifying the interested subscribers. In this case, when FORM_C fires the event, FORM_B is subscribed and interested.
When FORM_B receives the Call Back, the only thing it does is… notify the interested parties (in this case, FORM A) that the event was fired.
Now, even while Form C is still the top form, the callstack goes back to FormA, to the method defined as callback from the 1st event.
This code Executes. All it does is really somePanel.Invalidate() (or Refresh(), same results).
A Breakpoint in the PAINT method of that panel, reveals that the code doesn’t get called. No Paint event is raised despite being invalidated. I assume that happens because the form (and therefore the panel) is actually covered by FORMB and FORMC (still open).
And that’s all. If I close form C and then Form B, form A still DOESN’T raise the paint event. I’ve tried invalidating the panel on Form activation, but that doesn’t happen.
If I close the form A and reopen it, the drawing is, of course, correct.
Hope this makes it more clear.
There isn’t really much code as this is pretty simple, FORM A > B > C (fire event) -> B -> A -> Invalidate().
Try using Refresh() instead of Invalidate(). That seems to work more consistently for me, anyways.
I have a windows forms application, where I have declared some static variables.
On the click of exit button, I have disposed of some datatable which i have declared static.
Many a times the user instead of clicking the exit button, will just exit the windows application by clicking the X button on the left corner top.
What should be done to ensure that even if the user clicks the X button, everything is disposed of properly.
Thanks
Regards
Hema
This question has some good descriptions of events that you can hook into to detect when a application is exiting.
Does Application.ApplicationExit event work to be notified of exit in non-Winforms apps?
Just add a delegate function to the Closing event of the form.
this.Closing += this.MyForm_Closing;
You can also use the Closed event of the form if you'd prefer it gets called after the form is closed.
You can add an event handler to dispose your variables when the form is closing.
private: System::Void myDialog_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) {
// Dispose your static variables here
}