I have a winform application that can get pretty unresponsive during heavy calculations. For example, when user presses F10 key, the program will starts some heavy stuff and remains unrsponsive for a while (I know this is not a desired way of program flow but I don't want to alter the way program works at the moment).
Now the problem is, during this time if user presses F10 again, the program will start doing the same thing as soon as it has done the first process.
How to disable capturing keys at a certain point and enable it again?
The program is not "capturing the key", it is queued by the operating system because your main UI-Thread is busy with your calculations and doesn't handle anything at that time. The only thing i could think of what you could do is to check that a certain time has elapsed after the last run has finished before you allow another run. An ugly hack in my humble opinion.
But, yeah, thats why you should use backgroundworkers or threading. Using a BackgroundWorker is a lot easier than it may seem at the beginning.
Ideally you should use a BackgroundWorker here but as you said
I don't want to alter the way program works at the moment).
So I won't go into that path.
What you can do is when you detect F-10 for the first time set a bool value to true and next time whenever you detect f-10, check if the bool is already true or not. If it is already true don't start the heavy operation again simply skip the code.
At the end of heavy processing set the bool to false again.
I would agree with Jason on the whole - hacks and temporary fixes have a nasty habit of becoming 'features' of a program.
However, to answer your question, I would suggest having a disable flag in your program that disables the desired functionality whilst your calculations are running. You could then put in the event handler a check for the flag :
public bool DisableFlag { get; set; }
public void MyKeyEventHandler(object sender, EventArgs e)
{
if (DisableFlag)
{
return;
}
// Do stuff
}
Hope that helps!
Cheers,
Chris.
EDIT :
Thinking about Ken's comment, and this is true, the event will be queued and it will only be useful as long as some events are bleeding through. So, the other option is to disable the even handler altogether by doing
myControl =- MyKeyEventHandler;
and then
myControl =+ MyKeyEventHandler;
when the calculations are finished. This way, no events are queued and you avoid the problem as described by Ken!!
Related
sorry if this is a silly question, I am new to C#, so please give me a break.
I am working on Revit API. currently, Revit API doesn't support multi-threading operations.
my question is how to stop a loop without calling a new thread?
I am trying to get a snapshot and I am waiting for the user to pick a snap, so I put an infinite loop till the condition meets
while (!Clipboard.ContainsImage()) //loop till user get a clipboard image
{
}
but what if I want to abort this???
I have tried
private void Abort_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
abort = true;
}
}
but this method requires threading ....any suggestions!!
You want to look into asynchronous processing patterns in Revit - check for instance The Building Coders description of IExternalEvent.
It might take a little while to wrap your head around it, but let me try to explain:
Split your code up into two parts: The first part runs up until the moment you ask the user to pick a snap (I'm assuming this happens in another application?). In a separate thread, poll the clipboard (or register your application as a clipboard viewer) in your while loop. Don't forget to Sleep() while you're polling! As soon as your polling thread finds a picture, create an instance of an IExternalEvent subclass and post it to Revit. When Revit has some spare time, it will execute the Execute method, passing in a UIApplication that you can use to do the rest of your code.
Revit doesn't let you access it's API from multiple threads at the same time, but during the Execute method of an IExternalEvent subclass, you are guaranteed to be in the correct thread for running code.
You can also look into the OnIdling event - basically, this gets called each time Revit has some spare time too. So instead of using a while loop in a separate thread, you could just place your clipboard checking code in the event handler for the OnIdling event and create a mechanism (a flag) to tell you wether you are currently waiting for a snap or not...
I have a big project (30ish developed classes) and I want to make a loading bar for it. I have a current progress and total progress bars. I also have to roughly describe what is happening during the current process.
The way that I did it is manually (haters gonna hate) go through the most greedy process and did estimations of how long it is gonna take (when it is a for loop, just do step ups each iteration).
I read that Background_Worker would be much more smoother, but as I read on, it appeared to me that I still do have to go to every chunk of code and say that I want to increment the progress bar (The idea that I have to do it do describe the process made sense to me).
So my question was: is there a way to sort of encapsulate your method in a "block", which would automatically allocate the progress bar times? Or is there a more efficient way to do what I'm doing?
The best way would be to put your main processing in a different thread to NOT overload your GUI so it doesn't freeze up (user frustration) and then do your progress bar in the GUI thread (or make another thread for the bar, too). All depends on the preference.
But NEVER!! Freeze up the UI. The users just think it is dead and try to force close it.
is there a way to sort of encapsulate your method in a "block", which
would automatically allocate the progress bar times?
No, progress bar is for showing a progress, so you have to set the start, end and current state values form outside (from the caller), because only caller knows what is it going to execute and have, potentially, control over it.
Yes, it is possible, if you visualize infinit bar, that does not provide to a user some quantitative information about action executing, but informs to him, that something is going on. You also can provide some text description, that changes based on current action, so user can see that "something is going on there".
There is nothing worse from UX point of view, then leaving user uniformed, confused in front of the UI that is doing something, which is not clear.
So the both approaches are good, imo.
Perhaps a background worker with the progress bar. Use a global variable to store the progress.
public class SomeClass
{
public int Progress { set; get; }
public void Method1()
{
...
Progress++;
}
public void Method2()
{
...
Progress++;
}
...
}
As each method is called, increment the progress and call the background worker to report progress.
I know there are better solutions to this but this is just an idea.
I'm writing a program to help with a game. I need it to update the text box that shows the current exp value, on the forum load it does show the exp, I need it to update the exp like every 3 seconds.
How would I go about doing that?
Here is what I have so far:
Client C = Client.GetClients()[0];
Player P;
P = C.GetPlayer();
expTextBox.Text = ("Experience: " + P.Experience.ToString());
I am not sure if I need a timer (which i have tried and I am very bad at making) or if a backGroundWorker would be best.
Based on your comments, I would recommend that you update your UI when your player/s are attacking, and not use a timer. This will keep your UI the most up-to-date and will probably serve you better than a 3 or 10 second timer. You will have a method like this:
public void Attack(Enemy e)
{
//do your attack code
//did the enemy die?
KillEnemy();
//add exp just for landing a successful attack
AddExp(e);
}
public void AddExp(Enemy e)
{
CurrentPlayer.Exp += e.ExperienceGain;
//update the UI with the new exp
GameWindow.ExperienceBox.Text = CurrentPlayer.Exp;
}
This is of course more pseudocode, because I have no idea what your design looks like, but I've made quite a few games, and this is how I always do it.
Good Luck!
I would encourage you to use Timer if you go to the background worker with infinite loop that is okay but you need to take care of two things when you use background workers:
Updating textbox or any other UI won't work as it needs to be done from the main thread. so you need to check myTextbox.requireInvoke() function before.
Check if the background worker got a cancel signal to exist the infinite loop.
on the other side. you will consume some time when you use timers to update the text box. as the timer would go to the event processing cycle in the windows then fire the event and finally you will write the code in the timer event.
I have a C# .NET 3.5 app that prompts for a username and a PIN. I'd like the app to automatically reset if no PIN is entered for x seconds. If a key is pressed within x seconds, then the timer should reset to 0 and start again. I've searched around and found various methods for doing this, using a timer, thread.wait, but I haven't found something that was an example of what I'm trying to accomplish. I think the solution will involve using multiple threads, but I've never had to do this before so I'm not sure where to start on this.
Doesn't need to be that clever this, unless it's a behaviour you are going to reuse a lot.
Assuming you are showing this form modally
Put a timer on your form (disabled)
enable when the form is shown.
Add keydown/keypress eventhandlers to the boxes that could have focus
In them restart the timer
If the timer event fires close the form returning a suitable DialogResult Cancel should do it.
Seeing as you reset on keypress, little point in having another thread. If you weren't resetting then M Patel's answer is the way to go, unless you want to reinvent a lot of wheels
You could use the example here which uses the IAsyncResult interface and Action to do it. I myself have used it and it works like a charm. To simplify things just use it as in the example below
Action wrappedAction = () =>
{
// show your input
};
IAsyncResult result = wrappedAction.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
{
/// the user supplied an input and closed the form
wrappedAction.EndInvoke(result);
}
else
{
// the code has timed out so close your input and throw error
}
I am a bit new to threading (not new to C#, just haven't done much threading). Can someone explain to me why this does not work?
I have a thread which calls a method I will call "Loop". Loop contains a while loop which will continuously run, and on every loop of the while I want it to check if the A Key is down (using Microsoft's Keyboard class within the XNA Framework). But for some reason it never registers that anything is being pressed.
static Thread thread = new Thread(Loop);
static bool abort = false;
public static void Begin()
{
thread.Start();
}
private static void Loop()
{
while (!abort)
{
if (Keyboard.GetState().IsKeyDown(Keys.A))
Console.WriteLine("A pressed.");
}
}
Might anyone know why the Console.WriteLine() is never being called?
EDIT:
I guess I should explain a little bit. What I am actually trying to do is create something similar to ActionScript's events in C#. So I want to pass a "condition" and an "action" to call if that condition is met in this separate class which contains this thread. What this would do would allow me to just add "event listeners" to objects and it would automatically constantly check if one of the events gets triggered, rather than leave it to me to write If statements in code to check for the events.
Upon trying to do so, the first thing I tested was regarding this XNA Keyboard stuff, because it was one of the reasons I originally wanted to build this system, but it didn't work. So I created the standalone code which i posted above to see if I had made an error in my previous code and it still didn't work.
I never use XNA so I didn't really "know" but I've run into similar situations where you can't get keyboard (and other) input from a worker thread. I googled and found that in XNA this does seem to be the case. See this for example
So you need to (and probably want to) process your game input in the GUI thread. Just checking for input on each update tick should be fine. I doubt even if it did work, you would gain any performance - and you might introduce some interesting synchronization bugs ;-)
It does look like your creating your worker thread properly - this just isn't an application for it.