I have created some basic applications using windows forms C#.
What I am trying to achieve is that I have some task taking place inside a function. While executing that task I need to display a message box (with no buttons) with the text "Configuring...". I also need to blink this text. How can I do that?
Do I need to have another form for this? After completing this task this form needs to be hidden or closed?
I have googled this but couldn't see an answer, may be because of my unclear question in google.
If you really need a progress indicator you have to do as toATwork said, and do a Background worker
However, it is not a really async task, so you might find it hard to make it work properly
If you finally don't care about the message, and just need to show the users that something is happening, you can always use:
// To start
Cursor cursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
// To finish
Cursor.Current = Cursors.Default;
This will just put the mouse cursor in "loading", but it might work for you
You can use a label on your form and change its text in function Body.
{
//your function body
label.Text="Configuring";
}
Related
I am a beginner to the OOP and the C#.
I am working on a quiz game using the Windows Forms.
My problem is related to two classes, the form and the game logic.
I have a basic UI with classic Froms controls. Take a look.
The thing I want to achieve is, when a player presses any answer button, it will higlight that pressed button by red or green color, depending on if it is right or wrong answer. After changing the color I want the program to wait for a while and then go to the next question.
Probelm is, that I don´t know how to achieve this correctly. I don´t know how to work with threads and how exactly the Form app works related to threads. Should I use a thread sleep or a timer or a async?
I will show you the method in game logic class which should handle this.
public static void Play(char answer) //Method gets a char representing a palyer answer
{
if (_rightAnswer == answer) //If the answer is true, the button should become green
{
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.Color.LightGreen);
_score++;
}
else //Otherwise the button becomes Red
{
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.Color.Red);
}
//SLEEP HERE
if (!(_currentIndex < _maxIndex)) //If it is the last question, show game over
{
Program.MainWindow.DisplayGameOver(_score);
}
else //If it is not the last question, load next question and dispaly it and finally change the button color to default
{
_currentIndex++;
_currentQuestion = Database.ListOfQuestions.ElementAt(_currentIndex);
_rightAnswer = _currentQuestion.RightAnswer;
Program.MainWindow.DisplayStats(_score, _currentIndex + 1, _maxIndex + 1);
Program.MainWindow.DisplayQuestion(_currentQuestion.Text);
Program.MainWindow.DisplayChoices(_currentQuestion.Choices);
}
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.SystemColors.ControlLight);
}
I don´t want to completely block the UI but also I don´t want users to make other events by pressing other buttons during the pause. Because it will result in improper run of app.
If the program is really simple and you do not want to implement Threads I would suggest using Timer. Just start your Timer when clicking answer button. Your timer should contain function which would stop itself after some time and do other actions needed (e.g. pick another question).
Once the user has selected an answer you can disable all the buttons so they can't press anything else.
Then start a timer so you don't block the UI. The timer is basically a thread but handles all the threading for you so you don't have to worry about that aspect.
When the timer reaches the desired delay stop it and fire an event to select the next question.
At //SLEEP HERE add this line of code
Timer timer = new Timer(new TimerCallback(timerCb), null, 2000, 0);
The 2000 is milliseconds and is the wait time, timerCb is a call back method.
Also under that disable all your buttons so new events wont be generated.
private void timerCb(object state)
{
Dispatcher.Invoke(() =>
{
label1.Content = "Foo!";
});
}
You can do whatever you want in the callback, however if you do something that would change anything in the UI, you need to use the Dispatcher like I have changing the label content.
Suspending execution in a GUI scenario is very easy thanks to await:
await Task.Delay(2000);
This does not block the UI.
You should research what await does and how to use it. If you have never heard about it and are programming WinForms you are doing something wrong.
No timers or threads are needed. No callbacks, no Invoke.
I am using C# and Visual Studio 2013. I've read up on design patterns and I'm currently using the MVP design pattern.
My issue is that I start a Wait Cursor on the mouse and what I want it to do is go into an Aysnc function and perform the time consuming action, but keep the wait cursor going until the time consuming action is complete to assure people the program is still running. Outside of the MVP pattern I've done this before and the whole process works as it should. 1. start wait cursor, 2. start long function, 3. long function finishes, 4. change cursor back to default. However when I go from my presenter to my model from what I can tell in the debugger the wait cursor changes back to a default cursor as soon as the Async function begins.
I've done various tests to see if this affects all GUI components. It also affects marquee progress bars, but if I have a message box after my Async call it will activate the message box after the task is finished.
Is there something I'm missing that happens between the cursor being turned into a wait cursor and the task starting? I've looked around and I don't think anyone else has experienced this problem from what I can tell...
ex code: (please excuse sloppiness writing this from memory so syntax may be closer to pseudo code)
//View
//start wait cursor
public void StartWaitCursor()
{
Cursor.Current = Cursors.WaitCursor;
}
//stop wait cursor
public void StopWaitCursor()
{
Cursor.Current = Cursors.Default;
}
//Presenter
TheView.StartWaitCursor();//For some reason this goes to default cursor before task is finished
await Task_MethodAsync();
TheView.StopWaitCursor();
It is hard to determine anything from the pseudo code you provided.
From this article, the method from which you are calling Task_MethodAsync(); must be inside async method, in your Presenter. I may be wrong though.
Other than that, I'd start debugging and put a watch on your cursor and see with each step how/when it changes.
I'm working with MSVS2010 and am having trouble creating a status bar or status strip. I have a loop that does some things and runs some functions. It's a "while" loop. All I need to do is display some sort of form that says "busy..." or "working.." while inside of this loop. Does anyone have specific step by step instructions of how to accomplish this? I have looked at tutorials and examples online but I am not getting a clear idea of how to accomplish this. Any help on this would be great. Thanks in advance.
You could use a label for it.
Just add a label and name it for example stateLabel
Then in your code just do smth like this :
stateLabel.text = "Working..."; //Change the text of the Label
while(statement = true) //Your Loop
{
//Do your work
}
stateLabel.text = "Finished work";
Something simple is to use a progress bar with the 'marquee' style property, good to make user waiting on something.
So set the' marquee' property before the loop, and then you can back to default value and/or hide this progress bar after going out through the loop.
Am I enough clear or do you want some code example?
You could do something simple like change your cursor:
//change cursor to wait cursors
this.ForceCursor = Cursors.Wait;
//do loop
while(true)
{//do work}
//change the cursor back to regular arrow when work is completed
this.ForceCursor = Cursors.Arrow;
Or, so long as you aren't doing anything with UI controls in the while loop, you could do the loop on another thread. Just put a progress bar somewhere in your window (call it myProgBar), and make it indeterminant if you do not know how long the loop will take. Here is kind of how I would do it:
//create instance of loading window
YourLoadWindow loadWin = new YourLoadWindow();
//Create a thread that will do our loop work.
Thread t = new Thread(new ThreadStart(() =>
{
//do our looping;
while (true) {//do work}
//when loop is done, we want to hide the loading window
//but we created it on a different thread, so we must use its dispatcher to do
//the work from this thread
loadWin.Dispatcher.Invoke(new Action(() => { loadWin.Close(); }));
}));
//show load window
loadWin.Show();
//start doing our work
t.Start();
Here is what my code looks like:
private void exportToExcelButton_Click(object sender, EventArgs e)
{
txtBox.Clear();
txtBox.AppendText("Beginning Export...");
ExportExcel(txtBox);
txtBox.AppendText("Export complete...");
}
The problem I am having is that whenever the button is clicked (to execute the function above), only part of the current text in the TextBox (System.Windows.Forms.TextBox) is cleared, and replaced with the first line: "Beginning Export ...".
However once the function ExportExcel(txtBox) is done executing, then the entire text is replaced by the new one generated in ExportExcel(txtBox).
Inside ExportExcel(txtBox); I have several txtBox.AppendText() statements explaining to the user the actions being made.
I have tried clearing the text with txtBox.Text = String.Empty; and txtBox.Text = "";and neither have worked.
Let me know if anything needs to be clarified, thanks.
Looks like you're blocking the GUI thread, preventing the text box from redrawing itself. This is one reason why you shouldn't perform long-running tasks on the GUI thread. Use a background thread instead. That way you leave the GUI thread free to perform important operations like drawing, responding to mouse clicks, etc.
Have you tried the textBox.Refresh , before calling txtBox.AppendText("Beginning Export...").
The method invalidates the control.
On the other hand, if you use a background thread, then you should update the UI only by overriding the Progress Changed event. Background threads are not meant for updating user interfaces. Try searching for Worker threads and UI threads. They correlate to MFC, but the concept is the same.
Also keep in mind the cross thread calls.
I agree with dvnrrs. However if you are unable to do this, try calling txtBox.Refresh();after adding each line of text.
There is another method called Application.DoEvents(); that has a similar behavior, but its use is not recommended since it sort of short-circuits the normal application flow and can cause your application to fail unexpectedly or do strange things.
I'm tired and hungry, so I might of missed it, but from what I can see no existing post covers this...
I'm writing a plugin for an application. My plugin loads a form to get some data specifically, it uses the webcam to scan for a barcode. Once it's found a barcode, the form hides itself (incase it's needed again later). This is how I currently call the form that does the barcode work:
string readData = null;
if (eye == null)
{
System.Windows.Forms.Application.EnableVisualStyles();
eye = new CamView();
}
eye.Show();
if (eye.found)
{
readData = eye.readData;
}
return readData;
So, my problem is that eye.show() doesn't block. It makes the form appear and carries right on before there's a chance for the barcode to appear. I imagine I need to use some form of threading or locking, but my crude attempts to do so have just frozen the interface completely.
The "eye" form is basically just a viewfinder for the webcam, and relies on the camera_OnImageCapture event to make it do it's image checks for the barcode.
Is there an elegant way to make the application calling the plugin wait for the form to finish? Or do I just need to add an accept button to the "eye form?"
Cheers. And humble apologies if this is in anyway a repost.
.ShowDialog();
http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx
"You can use this method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed."
You are on the right track. You change the code to show CamView as a modal dialog but do no add an Accept button. Instead change camera_OnImageCapture to close the dialog.