Using c# winforms, I'm trying to make a sort of overlay. Here's what I'm testing with:
Main window has this code:
OverlayThread = new Thread(DisplayOrderOverlay);
OverlayThread.Start();
private void DisplayOrderOverlay(object obj)
{
ActiveOrderOverlay AOA = new ActiveOrderOverlay();
AOA.StartLoop();
AOA.ShowDialog();
}
And the overlay is just a list box on a form with this code:
public void StartLoop()
{
while (true)
{
Thread.Sleep(500);
Random r = new Random();
listBox1.Items.Add(r.Next().ToString());
this.Refresh();
}
}
I never even see the overlay, but if I pause, the loop is running.
AOA.StartLoop();
AOA.ShowDialog();
You're starting your loop and trying to show the dialog on the same thread, so until the loop finishes (it never will), AOA.ShowDialog() isn't called. Make the loop exit and you should see your dialog open. Or, you can also test by putting a breakpoint on the second line to see if it ever gets hit (you should have done this already).
while (true) loop will run forever and hence freeze you app. Normally you'd break of such loop on some condition to terminate the loop.
Possibly you are looking for Timer setup for every 500ms with handler that adds random number to a list.
Side note: check out Random number generator only generating one random number for proper creation of Random.
Related
For the sake of making a (shuffled) playlist, I've made a separate thread in which I load and play each song in the playlist. The background stuff (wav files, file paths, playlists and shuffling) all work without a hitch.
The issue is that I have 2 windows, each of which can close and open the other. Each window has a different playlist, and when I switch to the other window, I want my static SoundPlayer to stop playing, then start playing the new playlist.
This currently isn't working: currently, the application waits until the current track is finished before displaying the next window and starting the other playlist. Yes, the entire application waits on this.
I'm new to thread coding, so I'm not really sure what to do. The two methods of stopping this I've tried so far have been SoundPlayer.Stop() and Thread.Abort(). Neither changes the situation at all.
In each window:
Thread playlistThread;
public Window()
{
InitializeComponent();
MusicPlayer.music.Stop();
playlistThread = new Thread(() => MusicPlayer.PlayPlaylist(MusicPlayer.ShufflePlaylist(MusicPlayer.PlaylistFromType("[insert track type]"), random)));
playlistThread.Start();
PlayPlaylist which I will show next takes a List of strings, so don't worry about the Thread line, it's just a few sections put into one. The properties after that simply generate that list, and again, that all works, but I can show it if anyone thinks it's necessary. Here is the PlayPlaylist method:
public static void PlayPlaylist(List<string> tracks)
{
for (int i = 0; i < tracks.Count; i++)
{
music.SoundLocation = tracks[i];
music.PlaySync();
}
}
Here's the answer I worked out:
public static void PlayTrack(List<string> tracks, int i)
{
while (true)
{
if (i == tracks.Count)
{
tracks = MusicPlayer.ShufflePlaylist(tracks, MusicPlayer.random);
i = 0;
}
music.SoundLocation = tracks[i];
int l = SoundInfo.GetSoundLength(tracks[i]);
music.Play();
while (l > 0)
{
Thread.Sleep(1000);
l -= 1000;
}
i++;
}
}
The SoundInfo class with its GetSoundLength method I found here.
The reason this method works while others do not is because of how Play() and PlaySync() work. PlaySync() plays the entire .wav file in the current thread, with nothing else running until it finishes. Thus, even SoundPlayer.Stop() and Thread.Abort() do not work, as they insert a new line after the current one.
By running this method in a new thread, you avoid PlaySync() giving you that issue. However, it will still be impossible to stop the track ahead of time using PlaySync(). This is why you use Play() instead.
Therein lies a second issue, however: Play() plays the track in its own thread, meaning the rest of the code will continue. This is a big risk if you're wanting to do anything only after the current track finishes.
The answer is to calculate the length of the track you're going to play. Then simply create a while loop, running until l (given by GetSoundLength()) reaches 0. In each pass through the loop the thread (separate from your window's main thread) sleeps for 1 second. This is fine on the CPU and means that every second extra code, such as SoundPlayer.Stop(), can be injected into the thread.
I have a console app that does not terminate using a code
new System.Threading.AutoResetEvent(false).WaitOne();
What I want to achieve: I would want to run a StopWatch and if it meets a condition it will run certain file manipulating codes. And then finally after the block of code, resets the timer and wait for it to be true again to rerun.
Problem: However, upon debugging I cant get my code to go through my conditions even it has already passed the required condition.
My Code:
static void Main(string[] args)
{
string mutex_id = "41585f436f766572743243494d";
using (System.Threading.Mutex mtx = new System.Threading.Mutex(false, mutex_id))
{
if(!mtx.WaitOne(0,false))
{
return;
}
processTimer = new Stopwatch();
processTimer.Start();
if (processTimer.Elapsed.Seconds > 10)
{
processTimer.Stop();
fileQueue = Directory.GetFiles(ConfigurationManager.AppSettings["WatchPath"], ConfigurationManager.AppSettings["Format"]).ToList();
}
//process the fileQueue
//..
//..
//processTimer.Reset(); -> Reset Timer to wait for another 10 sec and process again
new System.Threading.AutoResetEvent(false).WaitOne();
}
}
I have used a FileSystemWatcher before but I failed to get the process correctly(Like Consecutive/Concurrent file creations and such). Tried Threading and Timers as my question.
Now I'm trying to approach this issue from a new perspective. Hope some can enlighten me with this.
There is no "try again" in your code.
The code you've written does the following:
Create a mutex and lock it
If it already exists, close application
Start a stopwatch
Check if 10 seconds elapsed (which they didn't)
Create a new AutoResetEvent and wait for ever for it
You will need some loop that periodically checks if 10 seconds have passed and otherwise Sleep
First of all - I'm very low skilled programmer. I am building the foundation of a simple music app for my bachelor degree project. My question is regarding a internal clock method that is meant to increase an int value by 1 BPM times a minute.
I've created an internalClock class:
public class internalClock
{
// THIS METHOD WILL BE CALLED WHEN THE THREAD IS STARTED
public static void clockMethod()
{
int BPM = 135;
int clockTick = 1;
Form1 clockForm = new Form1();
// infinite loop
while (true)
{
if (clockTick == 8)
{
clockTick = 1;
}
else
{
clockTick++;
}
clockForm.metrobox.Text = clockTick.ToString();
Thread.Sleep(60 * 1000 / BPM);
}
}
}
This is how I managed to get an access to the RichTextBox itself:
public RichTextBox metrobox
{
get { return metroBox; }
set { metroBox = value; }
}
In the main 'Program.cs' I've written what's meant to start a separate thread to run the clockMethod until the program is closed:
// THREADING
// Create a thread
internalClock oClock = new internalClock();
Thread oClockThread = new Thread(new ThreadStart(internalClock.clockMethod));
// Start the internalClock thread
oClockThread.Start();
It's not updating the text in the RichTextBox. Also, if I call the clockMethod() without creating a separate thread for it - the application freezes. Sorry for my amateur question, I'm just getting started with C# (yeah.. my uni is useless). What am I doing wrong in my code?
So the above code has several problems, however I would encourage you to check out the Timer control that you can add to the form you want to do processing at a certain interval or in certain "ticks". MSDN Form Timer
With the timer you can remove that class you have and invoking a new thread, etc etc. I would read up on the Timer class in the given link and think about how you can re-work your application structure to fit that. The concepts for why that thread isn't working, etc, is frankly not that important for where you're at. I think you just need to focus for now on a tool that already does what you want it to do, which I believe is the Timer.
As a general note, you usually don't need to create a raw thread in .NET. As of .NET 4.0 you can access types called Tasks to perform multi-threaded logic and processing. If you find the need to do that later on, check that out. Task Type MSDN
I have a simple label in C#.NET that does not seem to be "updating". It displays only the first initial values of my application. In the following code, the "score" variable does not update however it shows the correct value when the messagebox.show dialog is called. The score value is changed in a different thread, but I don't believe it to be a problem of invokes and cross thread form control (as I am calling this code in the thread that label6 was created on).
Does anyone know what might be a solution? I tried the Application.DoEvents() method with no avail. Also, neither label6.Update() nor label6.Refresh() seem to work when placed after the label6.Text = score line.
Player is a class I created holding the score value as a public int.
public Form1()
{
InitializeComponent();
createGame();
}
public void createGame()
{
InitializeComponent();
drawThread = new Thread(draw);
MessageBox.Show(player.score);
label6.Text = player.score;
}
public void draw()
{
//do drawing, change player.score value
//end thread
}
public void button_click()
{
if(firstrun)
drawThread.Start()
else{
createGame()
drawThread.Start()
}
}
EDIT (from comments):
This is a WinForms application.
The label6.Text = score line is the ONLY instance where label6 is called other than being instantiated in the Form.Designer code generated by Visual Studio.
just do Refresh() on the label.
label6.Refresh();
In your code I see
drawThread = new Thread(draw);
but on button click you call draw.Start() so I think your rendering thread is not started at all! Shouldn't you use drawThread.Start()?
More: you cannot access graphical controls properties from a thread different from the main, you should use Invoke...
I see a problem here:
drawThread = new Thread(draw);
MessageBox.Show(player.score);
With these lines second thread is started and MessageBox is showed immediately (second thread is not terminated yet probably)
label6.Text = player.score;
When you close MessageBox this line is executed: if second thread is terminated and has already updated score you will get expected result; if second thread is still executing, in your label you still find previous score.
So without knowing what your second thread does, I cannot know if your code is correct or not.
In my opinion you should update label6.Text from your second thread (using Invoke) when it's terminated; if not, why are you using a second thread?
Usually we use threads to perform long executions without blocking main thread (which takes care of updating form and process user input), so you should update properties from these threads when it's needed.
Think about using BackgroundWorker.
I'm working on writing a splash screen that returns a game mode (int) and an IP address (string). The idea is the splash screen runs, takes user input and then runs the main game with these options. I'm using a thread to achieve this - the thread polls for an exit request from the splash screen, then pulls the values out to program.cs and calls exit() on splash.
The main game runs on it's own with no issues but with the splash screen enabled the game runs just 1 frame and seems to be disposed of by garbage collection after running the update method. (returns a DisposedObjectException or something of the sort if trying to reference it) After a bit of debugging I've found the issue is with the exit command. Code is as follows:
using System;
using System.Threading;
namespace SplashScreen
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
int choice = 0;
string ip = "";
bool runSplash = true;
bool useThreading = true;
bool ignoreThreadResponse = false;
// Debug option, toggle running splash screen
if (runSplash == true)
{
bool splashrunning = true;
using (Splash1 splash = new Splash1())
{
if (useThreading)
{
// Run a thread to poll whether the splash screen has requested an exit every 0.5 seconds
Thread t = new Thread(() =>
{
while (splashrunning)
{
// If splash requests exit pull gameMode choice and IP Address before killing it, then quit this thread
if (splash.requestingExit)
{
choice = splash.choice;
ip = splash.ip;
// The offending piece of code, without this you can simply select an option, force close and second part runs fine
//splash.Exit();
splashrunning = false;
}
Thread.Sleep(500);
}
});
t.Start();
}
splash.Run();
}
}
// If splash screen is not running, assign default values
if(!useThreading || !runSplash || ignoreThreadResponse)
{
choice = 2;
ip = "127.0.0.1";
}
if (choice != 0)
{
// This game is picked up by garbage collection after running Update once
using (Game1 game = new Game1(choice, ip))
{
game.Run();
}
}
}
}
}
When splash.Exit() is called, it causes game1 to be collected after the first update. If I disable threading it works fine. If I exit using the X at the top right it works fine. Whether or not I ignore the thread response the game fails to run if threading is enabled and I call splash.Exit().
What I'm looking for is any of the following:
A reason why the second game is being collected.
An alternative way to exit a game or call the 'close window' (big red x) function.
A better way of implementing this.
I've used console input to do this in the past, but I want to move on to using a graphical interface instead of an ugly command prompt for the user.
Edit:
Turns out I was almost there. While GSM is probably the correct way of doing things, for anyone who just wants to grab the code from the question and throw caution to the wind you simply need to add a thread to run the second game.
I'm pretty sure this isn't ideal, but it's a lot less tweaking in my case.
Thread gt = new Thread(() =>
{
using (Game1 game = new Game1(choice, ip))
{
game.Run();
}
});
gt.Start();
So while I'd recommend anyone starting from scratch to use GSM, this might be a quick solution for someone else just trying to get it running.
What does your Splash class look like? Exit is a method of the Game class, and exits the game. Is your Splash class inheriting Game? If so, it shouldn't.
Edit:
After reading the bottom half of your post a bit more clearly - you should only have a single class that inherits from Game, and it should run your game. If you want to display a splash screen it should be a custom class, or look into the Game State Management sample.