C# Timer Tick Event Working Principal - c#

I have a c# form that draws some curves on it. I am trying to draw these curves at a specified interval with random values. I was able to do what I want, but there is a situation that I cannot answer. In the cases below, case 1 has the form repainted very very fast despite the fact that I am using 5 second interval. However, in case 2 if I moved the "Invalidate();" to the other part, then the code works as it is supposed to.
What is the reason for that situation?
Thank you...
Case 1:
private void hizlariHesapla()
{
if (RastgeleDegerCheckBox.Checked == false)
{
// Some code blocks
}
else
{
// Some code blocks
Invalidate();
}
Hesapla(); // Not important for the case
}
private void SurekliCizdir_Tick_1(object sender, EventArgs e)
{
if (RastgeleDegerCheckBox.Checked == true)
{
hizlariHesapla();
}
}
Case 2:
private void hizlariHesapla()
{
if (RastgeleDegerCheckBox.Checked == false)
{
// Some code blocks
}
else
{
// Some code blocks
}
Hesapla(); // Not important for the case
}
private void SurekliCizdir_Tick_1(object sender, EventArgs e)
{
if (RastgeleDegerCheckBox.Checked == true)
{
hizlariHesapla();
Invalidate();
}
}

It sounds as if your Hesapla method can directly or indirectly call back into the hizlariHesapla method. With the Invalidate call outside the loop you will only see it repaint once per timer tick but when it's inside you see the repaint for every time hizlariHesapla is called. Put a breakpoint there and look at the call stack.

Related

C# wait for timer to end before starting an other timer

Hi I'm making a UI in Windform and using timers. It's all quite new to me so my understanding of it is kinda of weak. I use timers to make a side menu animation.
The 1st timer is to show the menu. Something like this :
private void ShowFullToolsTimer_Tick(object sender, EventArgs e)
{
FonctionsNatives.dessinerOpenGL();
if (editionToolsMenu.Width >= 200)
ShowFullTools.Stop();
else
editionToolsMenu.Width += 5;
}
And to hide the side menu I have something similar :
private void HideFullMenu_Tick(object sender, EventArgs e)
{
if (editionToolsMenu.Width > 0)
editionToolsMenu.Width -= 5;
else
HideFullMenu.Stop();
}
The probleme I have is that I want one animation to be COMPLETELY over before starting the other one. I've been using Application.DoEvent(); if the timer.Enable is true, but i'm aware that it's terrible to do that and causes even more bugs. Any solutions?
EDIT1: Sorry for not being precise. Both timer start when a diffrent component is clicked. I also cant write both of the to end, for example:
ShowfullMenu.Start():
HideFullMenu.Start();
Since one does += and the other does -=. They'll be stuck in an infinite loop. Putting the thread to sleep stops the whole UI.
Stop the other timer when you are animating one menu and then restart it once you are done animating (and vice-versa). Here is some non tested code:
private void ShowFullToolsTimer_Tick(object sender, EventArgs e)
{
FonctionsNatives.dessinerOpenGL();
if (editionToolsMenu.Width >= 200)
{
ShowFullTools.Stop();
// start the other one
HideFullMenu.Start();
}
else
{
editionToolsMenu.Width += 5;
if (HideFullMenu.Enabled)
{
HideFullMenu.Stop();
}
}
}

Check if event (doubleClick) is running

I am writing a tool which switchs between a lot of states. For some events I need to be sure they wont get executed a second time while the called function (inside the event) is running. This is how I managed it before:
// Global variables //
public bool func1IsRunning = false;
public bool func2IsRunning = false;
...
public void listView_DoubleClick(object sender, EventArgs e)
{
if(!func1IsRunning)
{
func1();
func1IsRunning = false;
}
}
public void func1()
{
func1IsRunning = true;
// some code in here //
}
But with every extension of my tool the list of the global variables grows up. Also the events and functions getting less clear to read.
Isnt there a way like this(?):
public void listView_DoubleClick(object sender, EventArgs e)
{
if(DoubleClick.IsHandled)
{
func1();
}
}
public void func1()
{
// some code in here //
// ................. //
DoubleClick.IsHandled = true; // at the end of the function //
}
So what I am looking for is a way to determine if an event is still running or not. My code is working, im just unhappy with how it looks like.
Any ideas?
UPDATE 1
I decided to use Steve's answer as it solves my problem by the clearest way.
Anyway it is NOT running correctly for now.
Here is how my code looks like:
public void listView_DoubleClick(object sender, EventArgs e)
{
try
{
listView.DoubleClick -= new EventHandler(listView_DoubleClick);
itemEdit();
}
finally
{
listView.DoubleClick += new EventHandler(listView_DoubleClick);
}
}
The code above is NOT disabling the handler.
public void listView_DoubleClick(object sender, EventArgs e)
{
try
{
listView.DoubleClick -= listView_DoubleClick;
itemEdit();
}
finally
{
listView.DoubleClick += listView_DoubleClick;
}
}
This code is also not disabling the handler.
This is the line where the handler gets enabled (MainForm.Designer.cs):
this.listView.DoubleClick += new System.EventHandler(this.listView_DoubleClick);
There are no errors raised. The event just gets fired again and again. Where is the problem?
UPDATE 2:
As Sinatr asked in the comments below if my function is really waiting or just enabling user input he discovered where the mistake was made.
Steve's answer is correct according to my wrong written question. Thanks a lot to all of you guys.
Just disable the event handler
public void listView_DoubleClick(object sender, EventArgs e)
{
try
{
listView.DoubleClick -= listView_DoubleClick;
// Now, even if func1 causes a DoubleClick event,
// or user manages to trigger a DobuleClick
// there is no event registered and this code could
// reentered until you exit from func1.
func1();
}
finally
{
// Important part. the finally block is required
// because you should readd the event handler
// ALSO in case an exception occurs in func1
// and it is not handled there
listView.DoubleClick += listView_DoubleClick;
}
}
EDIT
Looking at your comment I suspect that this DoubleClick event is assigned to more than one control. If this is the case, using the global listView global instance of a listview doesn't disable the double click on other controls that are linked to the same code.
If this is the case then you need a more generic approach
public void listView_DoubleClick(object sender, EventArgs e)
{
Control c = sender as Control;
try
{
if(c != null)
{
c.DoubleClick -= listView_DoubleClick;
// Now, even if func1 causes a DoubleClick event,
// or user manages to trigger a DobuleClick
// there is no event registered and this code could
// reentered until you exit from func1.
func1();
}
}
finally
{
// Important part. the finally block is required
// because you should readd the event handler
// ALSO in case an exception occurs in func1
// and it is not handled there
if(c != null) c.DoubleClick += listView_DoubleClick;
}
}
Of course, this is just to enable/disable DoubleClicks events, it cannot works if you assign this event handler to other standard events like Click that have the same signature (object sender, EventArgs e)
How about something like the following using locks:
private object globalLock = new object();
private Dictionary<int, object> lockObjects = new Dictionary<int, object>();
public void listView_DoubleClick(object sender, EventArgs e)
{
object lockObject;
lock (globalLock) // to avoid two threads creating the object
{
if (!lockObjects.ContainsKey(1))
lockObjects.Add(1, new object());
lockObject = lockObjects[1];
}
if (Monitor.TryEnter(lockObject) // enter only if no thread has already entered
{
try { func1(); }
finally { Monitor.Exit(lockObject); }
}
}
This is different to Steve's logic in the matter that it is thread-safe.
A simple state-machine should solve your problem without requiring too many variables. Create an Enum named AppState like this:
enum AppState
{
Ready = 1,
InsideListView1Click = 2,
InsideListView1DoubleClick = 3
InsideListView2Click = 4,
InsideListView2DoubleClick = 5
}
This enum could grow as you add new controls and/or event-handlers to your application. Now use a single global variable that keeps track of the application state and modify it inside event-handlers appropriately:
private AppState m_State = AppState.Ready;
And in the event-handlers you would do:
private void ListView1_DoubleClick(object sender, EventArgs e)
{
lock
{
if(m_State != AppState.Ready)
return;
else
m_State = AppState.InsideListView1DoubleClick;
}
//Do your stuff
m_State = AppState.Ready;
}
This way newer calls will be ignored instead of being queued. If you expect to be in multiple states at the same time, you could apply [Flags] attribute on this enum as well. Also note that enums are thread-safe and evaluating them is atomic, so multi-threading shouldn't be a problem either.

How to use BackgroundWorker in C#

How to use BackgroundWorker in C#?
Actually i'm performing an operation of filling a PDF-Form from method called fill(). It takes more time to show up the result into pdfviewer, so I decided to show up a 'processing image' using a backgroundworker, and tried using it but failing to achieve it
here is my code snippet :
private void bgwLoadFile_DoWork(object sender, DoWorkEventArgs e)
{
this.Invoke((MethodInvoker)delegate()
{
????
});
}
private void bgwLoadFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
}
else if (e.Error != null)
{
}
else
{
picLoading.SendToBack();
}
}
Fill method is called when button FILL is been clicked
private void btnFill_Click(object sender, EventArgs e)
{
if (btnFill.Text == "Fill")
{
bgwLoadFile.RunWorkerAsync();
picloading.BringToFront();
Fill();
}
wat statement should i need to add in DoWork method , if i tried to add FILL() fill is been called twice ...
can any one help me out
Thanks
Add Fill(); to your bgwLoadFile_DoWork and remove it from btnFill_Click
Just a side-note you'll probably want to call your picLoading.SendToBack(); outside of that 'else' as if you error or cancel it will stay there.
So let's try to find some answers:
The method worker_DoWork() will be executed within another thread. By calling within that method this.Invoke() you're going to pass the call back to the gui thread, which makes the usage of the background worker useless. Instead within the worker method you have to call the method that needs some time and doesn't interact with the gui. If this called method produces any result (e.g. has a return value) you should write this information into the variable e.Result.
The method worker_RunWorkerCompleted() will be called within the gui thread again. Allowing you to take the result and let it somehow interact with the gui. Due to the fact, that this method will be executed on the gui thread it should be quite simple (or fast) in its doing otherwise your gui is going to freeze again.
So given these informations lets clean up your code:
private void btnFill_Click(object sender, EventArgs e)
{
if (btnFill.Text == "Fill")
{
// Update the gui for the user
// and start our long running task
// (disable buttons etc, cause the
// user is still able to click them!).
picloading.BringToFront();
bgwLoadFile.RunWorkerAsync();
}
}
private void bgwLoadFile_DoWork(object sender, DoWorkEventArgs e)
{
// Let's call the long running task
// and wait for it's finish.
Fill();
}
private void bgwLoadFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// We're back in gui thread.
// So let us show some results to the user.
if (e.Cancelled)
{
// To support cancellation, the long running
// method has to check some kind of cancel
// flag (boolean field) to allow fast exit of it.
labelMessage.Text = "Operation was cancelled.";
}
else if (e.Error != null)
{
labelMessage.Text = e.Error.Message;
}
// Hide the picture to allow the user
// to access the gui again.
// (re-enable buttons again, etc.)
picLoading.SendToBack();
}

Threading in wpf GUI thread is too slow

My application has work to do in background in another thread and the Gui drawing result from list the background thread fill this list
In initialization I made the background thread and when I press button in Gui this thread begin working ; and I click on another buttom to read result while the background thread working but The GUI is very very slow to response to result.
is there any solution I want my results display on GUI faster ?
my code:
Thread startdrawingthread = new Thread(StartDrawing);
public MainWindow()
{
InitializeComponent();
}
private void bt_draw_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (ch_single.IsChecked == true || ch_entire.IsChecked == true)
{
currentMode = "";
startdrawingthread.Start();
//StartDrawing();
real_area.DrawingArea.Children.Clear();
real_area.DrawGrid(20);
}
}
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (GlobalV.isfinished == false)
{
while (true)
{
if (GlobalV.Attatched_Elements.Count > 0)
{
try
{
real_area.DrawingArea.Children.Clear();
real_area.DrawGrid(20);
real_area.DrawElement(GlobalV.Attatched_Elements[i]);
i++;
}
catch
{
}
break;
}
}
}
}
You've committed sin #1 in asynchronous programming.
You have a busy loop. Instead of waiting for GlobalV.Attatched_Elements.Count to change, you constantly, non-stop ask "is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now? is it nonzero now?", as fast as the CPU can do it.
In other words, you're wasting a lot of execution time.
What you want to do is simply subscribe to an event telling you when Count changes. Then, when it changes, you check if it is nonzero, and perform the necessary processing.
The problem is, as long as GlobalV.Attatched_Elements.Count is zero, your event handler goes through an endless loop of while (true).
I guess that GlobalV.Attatched_Elements.Count is set somewhere in StartDrawing, but you can not busy-wait like this until it gets greater than zero. You should perhaps remove the whole if (GlobalV.isfinished == false) and while (true) blocks and simply do the following, which especially does nothing if there is nothing to do:
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (GlobalV.Attached_Elements.Count > 0)
{
...
}
}
maybe with also locking the collection for thread-safe access:
private void bt_single_next_Click(object sender, System.Windows.RoutedEventArgs e)
{
lock (GlobalV.Attached_Elements)
{
if (GlobalV.Attached_Elements.Count > 0)
{
...
}
}
}

breaking out of my infinite loop

I have two buttons one for start and one for stop in my UI form,and i have one infinite loop that executes some function in my class name programs in a method.The start button is clicked by the user it invokes this method to execute the infinite loop and i need to break this infinite loop when the user clicks the stop button,after that my compiler will break out of this infinite loop and enters to the code inside the button stop click.
I am trying to use the Application.DoEvents() method,this is working well if my infinite loop code is inside of the start button click,but if my infinite loop code is in the new class which is created by me i.e programs,how can use the Application.DoEvents() method to break out of this infinite loop.
Example:
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
this is working well.
But
public class programs
{
public static void infiniteLoop(bool stopBtnClick)
{
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
}
//and my UI code to call this class is
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
programs.infiniteLoop(stopBtnClk);
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
}
but this is not working .
Even if the compiler displays the message "success" when the stop button is clicked, but the debugger still said running in my form.
I hope my question is clear.
And i am kindly requesting you to answer my question as soon as possible and get rid of this problem!
I openly accept your answer if you come especially with a thread.
sorry i am a beginner for C#, but i need to continue on that.
Thank you!!
Don't block the GUI thread. The fact that you have to use Application.DoEvents() to update the GUI is an indicator for bad design. Do the work in a separate worker thread.
BackgroundWorker is predestinated for such a task.
Change signature of your infiniteLoop method like this:
public static void infiniteLoop(ref bool stopBtnClick)
...
The code you have provided is really difficult to read but as far as I can see when you create your infinite loop do:while(looping) // do stuff
Then when you press the Stop button set the bool variable looping to false and it will break out of the loop and show the message.
In the second code snippet, the infinite loop is started in a subroutine that accepts a boolean value as a parameter. How does that subroutine ever get a second chance to take a look at that boolean? It only "sees" the value once, and it's false at that time. It's a scoping question.
Why instead of an infinite loop you use a start stop condition determined by the buttons?
I thinking you can have a variable, just call it
bool stop_loop = false
and your loop
while(!stop_loop){ //CODE HERE }
Now when you click the first button (Start) you call the method (wherever it is) to start the loop. The loop is going to seem endless until you click the button stop and the value of stop_loop become in True.
HTH

Categories