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.
Related
I have a Windows form program which controls a light. This light has its own class. I can do things like turn it on an off and change the color etc. This I can do without issue. What I want to be able to do, however, is make the light go on for a specific amount of time, i.e. 100 milliseconds or 300 milliseconds (depending on use).
I have tried to used stopwatch to do this, but when I click on the button that is meant to do this, it freezes the program. The light goes on, then doesn't turn off, and I can't use the stop button I have which is meant to turn it off.
The program loads the light, and initialises it, and displays an alert saying it has done this and detected one light. Then I use this:
private void Red_Click_1(object sender, EventArgs e)
{
//Displays Red
System.Threading.Tasks.Task.Factory.StartNew((Action)delegate()
{
displayRedDot();
});
}
This is the displayRedDot()
public void displayRedDot()
{
System.Diagnostics.Stopwatch clock1 = new System.Diagnostics.Stopwatch();
long elapsedTime = clock1.ElapsedMilliseconds;
clock1.Start();
while (elapsedTime < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
oBlynclightController.Display(BlynclightController.Color.Off);
clock1.Stop();
}
I have some other functions, which are identical this with a different time, which I haven't invoked anywhere yet because I can't get this to work.
Your code will never work since you are blocking the UI thread by busy waiting. This is the reason for your program seems to freeze. Use a timer or async/await instead
async void DisplayRedDot(int duration)
{
oBlynclightController.Display(BlynclightController.Color.Red);
await Task.Delay(duration);
oBlynclightController.Display(BlynclightController.Color.Off);
}
elapsedTime will never change its value. You initialize it right after creating the stopwatch, but never assign a new value to it. Stopwatch.ElapsedMilliseconds is a long. long is a value type. A copy is created and assigned to elapsedTime. You need:
while (clock1.ElapsedMilliseconds < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
Note that this loop is going to run very quickly until that check returns false. Is this really what you want? I don't know exactly what your code is doing (you don't show us), but why not just set the color to red, wait 100ms, and then set it to... erm, Off.
It's also difficult for humans to pick up a change that only lasts 100ms. It's going to be a flicker at best.
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 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 making a media player, now.. I have added a realtime search function to search for songs etc. (Some thing like WMP realtime search) i.e while you enter the keywords the searching happens.
During the searching process, accessing the database and loading an IEnumerable is done on another thread via a BackGroundProcess. The UI is updated by invoking a dispatcher of a UIElement.
This process is rather fast, but however while you enter the search keywords in the textbox, there seems to be a small lag, this is beacause the Listbox.ItemSource updating takes some time.
i.e say you want to search for "Adele", when you type in "a", the search function loads the results for "A", but as we are typing the whole word "Adele" , it some time to display the "d" "e" "l" "e" and there is a slight lag in between these letters.
During this search process, when I stop updating the UI the search process seems very smooth, this only means to me that the Listbox is locking up the thread, so the rest of the player's UI is stuck there while the Listbox is done with its processing.
So I believe if I can put the Listbox Control to another UI thread, I can maintain the smooth flow of the player irrespective of the time taken to load the Listbox.
FYI: Data Virutualization is there & ListBox has UI Virtualization is working
How can i put the ListBox control onto another UI Thread?
WPF, C#
Thanks in advance :)
If you are querying the database on every keypress - this is going to cause you some lag when typing fast (or even normally)
You would be better off throttling the request, we use this to throttle on the dispatcher thread.
public static class DispatcherExtensions
{
private static Dictionary<string, DispatcherTimer> timers =
new Dictionary<string, DispatcherTimer>();
private static readonly object syncRoot = new object();
public static string DelayInvoke(this Dispatcher dispatcher, string namedInvocation,
Action action, TimeSpan delay,
DispatcherPriority priority = DispatcherPriority.Normal)
{
lock (syncRoot)
{
if (String.IsNullOrEmpty(namedInvocation))
{
namedInvocation = Guid.NewGuid().ToString();
}
else
{
RemoveTimer(namedInvocation);
}
var timer = new DispatcherTimer(delay, priority, (s, e) =>
{
RemoveTimer(namedInvocation);
action();
}, dispatcher);
timer.Start();
timers.Add(namedInvocation, timer);
return namedInvocation;
}
}
public static void CancelNamedInvocation(this Dispatcher dispatcher, string namedInvocation)
{
lock (syncRoot)
{
RemoveTimer(namedInvocation);
}
}
private static void RemoveTimer(string namedInvocation)
{
if (!timers.ContainsKey(namedInvocation)) return;
timers[namedInvocation].Stop();
timers.Remove(namedInvocation);
}
}
Assuming you are not using MVVM, you could easily use this like so in your button click
Dispatcher.CurrentDispatcher.DelayInvoke("UpdateSearch",
YourMethodThatStartsBackgroundThread,Timespan.FromSeconds(1));
Also worth a note : f you are using 4.5 there is the Delay property on bindings you could look at.
In ASP.NET, usualy we use two techiniques
Wait for at most 3 char to begin the search.
Waiting some milliseconds after de user stop typing and before start the search, as the user types fast than some miliseconds, your search term will contains more than one char.
This second option consists in start a timer when the user start to type and set this timer to zero (without stop it) every key pressed. When the user stops to typing for 2000 milliseconds (by example) you perform the search
A perfect approach is to combine this two techiniques: Only search if you have 3 or more chars in the search criteria, and use the timer.
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!!