I would like to know if there is a way to do two things in a Console App for C# Code.
First one, is to show the progress percentage of a called process, so that, the user will will know more or less the elapsed progress and how much he/she needs to wait.
Second one, is to print three strings which constantly change, looping each one, until the process finishes.
Those are the Strings I would like to Print, one after another, but on the Same Line of the Console App Screen:
string Please_Wait_One_Dot = "Please wait.";
string Please_Wait_Two_Dots = "Please wait..";
string Please_Wait_Three_Dots = "Please wait...";
Console.WriteLine("\n{0}", Please_Wait_One_Dot);
Console.WriteLine("\n{0}", Please_Wait_Two_Dots);
Console.WriteLine("\n{0}", Please_Wait_Three_Dots);
// This Prints those Strings but on Different Lines without any Loop.
Basically, what I want to do is to Print some Text which shows an Message but, the Number of Dots Changes from 1 to 2 and from 2 to 3 and then it Changes back to 1, Looping this Cycle until the Selected Operation by the User is Finally Done.
NOT TESTED... use as pseudo code...
Console.write("Please_Wait");
int count = 0;
do
{
if (count < 3)
{
Console.Write("."); // add a dot
count++;
}
else
{
Console.Write("\b\b\b"); // erase all dots
count = 0; //resume
}
} while(not_done)
I have a dataGridView where I run a Process for each entry
and then update a toolStripProgressBar based on the output from the Process.
I have looked at the following threads,
Run two async tasks in parallel and collect results in .NET 4.5
Progress bar in parallel loop invocation
how to update the progress bar from tasks running concurrently
but I am not sure how to change my current code to something along these lines.
The main difference from these threads, as I see it, is that my computations are done by an outside application,
which I then need to collect the output from.
I guess I have to define each Process as an async task and then somehow collect the output.
For simplicity the processes are equal weighted in the sample code.
private iNumProcesses;
private void RunApps()
{
iNumProcesses = dataGridView1.Rows.Count;
string sPath = .exe application path
for (int i = 0; i < iNumProcesses; i++)
{
string sArgs = dataGridView1.Rows[i]["Arguments"].ToString();
ExecuteProgram(sPath, sArgs);
}
}
private void ExecuteProgram(string sProcessName, string sArgs)
{
using (cmd = new Process())
{
cmd.StartInfo.FileName = sProcessName;
cmd.StartInfo.Arguments = sArgs;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.ErrorDialog = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmd.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmd.Start();
cmd.BeginOutputReadLine();
while (!cmd.HasExited) { Application.DoEvents(); }
}
}
private void SortOutputHandler(object sender, DataReceivedEventArgs e)
{
Trace.WriteLine(e.Data);
this.BeginInvoke(new MethodInvoker(() =>
{
if (e.Data == "Start") { do something... }
else if (e.Data == "Finish") { do something... }
else if (e.Data == "End") { do something... }
else
{
// .exe application output numbers 1 through 100
toolStripProgressBar1.Value += Math.Round(Convert.ToInt32(e.Data)/iNumProcesses,0);
}
}));
}
How can I run the processes in parallel and update the progress bar
based on the output numbers 1 through 100 I get from the .exe applications?
Any advice or suggestions will be greatly appreciated.
My answer to this question is not particularly associated with "C#" and therefore I'm not going to speak directly in those terms: this unexpectedly-thorny issue is actually universal.
The first thing that you must do is to arrange to periodically update the user display. To avoid nasty race-conditions and other problems, you should have "the main thread" perform this task, driven by a millisecond timer. The thread consults a shared array of progress-information and updates all of the progress-bars accordingly. (If you want to use an event to avoid outright "timed waiting," feel free to do so.)
Since each of the launched child processes will have their own input and output streams, and will be writing to those streams asynchronously, you will find it necessary to spawn a "mommy thread" within your application to supervise each child. This thread corresponds to a particular external process, and, in fact, is the one that launches it. The thread continues to exist until it determines that the process that it launched has died.
The "mommy thread" observes the output-stream(s) of its appointed ward to determine its "progress." It updates the progress-variables in the shared array accordingly. (A key element of this design is that each "mommy thread" is able to pay 100% of its attention to just its child. And, because all the "mommies" are threads, they can easily share information with the thread that's updating those progress bars.)
Do you actually have to use semaphores-and-such to coordinate access between the mommy-threads and the main? Depending of course upon the exact internal implementation of that data-structure, the answer just might be, "probably not." (Oh, but it's probably safest to do it anyway.)
Pls i am doing a simple application like a calculator. The application listen to key press and update display based on the key pressed. The application display like a simple calculator with numbers all written form the console.write. How ever, it display the same whole output when ever a new console is written. I want to replace the existing text with the new one at the same spot in such a way that user may not realized the the effect . Please is there any way i can achieve this in console ?
I came across a similar question How can I update the current line in a C# Windows Console App?>Here . However, mine is quite long next with many lines writen below
public static void writeTiles(int[][] tiles)
{
for (int i = 0; i < iBoard.Count(); i++)
{
for (int j = 0; j < iBoard[i].Count(); j++)
{
Console.Write(Indent(2) + iBoard[i][j]);
}
Console.WriteLine();
}
// Console.ReadLine();
}
please how do i achieve that ?
I am trying to figure out why a program I am working on goes in to "not responding" mode when I ask it to output a large amount of characters to the console it is running in.
I tried creating a small example that just prints out characters, and this will indeed also go "not responding" on me after some 10-20 seconds:
static void Main(string[] args)
{
for (int i = 0; i < 255; i = (i+1) % 255)
{
Console.Write(((char)i));
}
}
The program is still running though, even though the console window is "not responding", I can still pause the debugger and continue it, but the console window is broken.
The thing is, the console do not mind spitting out an endless amount of integers:
static void Main(string[] args)
{
for (int i = 0; i < 255; i = (i+1) % 255)
{
Console.Write(i);
}
}
Any ideas is much appreaciated. Thanks!
When you cast it to a character, you're also sending control characters to the console for some lower values of i. I'd guess is has something to do with outputting some of those control characters repeatedly.
Well it will spew out a lot of nonsense (and beep a lot, unless you mask out character 7, which is a bell) but it never becomes unresponsive for me.
It will depend on how your console handles control characters though - which console are you using, on which operating system and with which language?
Moreover, why do you want to send unprintable characters to the console? If you keep your loop to ASCII (32-126) what happens? For example:
using System;
class Test
{
static void Main(string[] args)
{
int i=32;
while (true)
{
Console.Write((char)i);
i++;
if (i == 127)
{
i = 32;
}
}
}
}
Does that still exhibit the same behaviour?
You mention the debugger - do you get the same behaviour if you run outside the debugger? (I've only tested from the command line so far.)
Just as an aside, you can omit i<255 and simply write:
for (int i = 0; ;i = (i+1) % 255 )
or to go with Jon's answer you can simplify that like this
using System;
class Test
{
static void Main(string[] args)
{
for(var i=0;;i=(i+1) % 126)
{
Console.Write((char)(i+32));
}
}
}
I am writing a server app and I want it to be console based. I need the user to be able to input different commands, but at the same time there is a possibility that something will be output to the console while the user is writing. This messes the buffer up. Is there any clean way of doing this?
Thanks.
I started work on a test program to show how you could divide the console into an output area and an input area, where the input area is moved down as the output area expands with more output. It's not perfect yet, but you may be able to develop it into the answer you're looking for:
static int outCol, outRow, outHeight = 10;
static void Main(string[] args)
{
bool quit = false;
System.DateTime dt = DateTime.Now;
do
{
if (Console.KeyAvailable)
{
if (Console.ReadKey(false).Key == ConsoleKey.Escape)
quit = true;
}
System.Threading.Thread.Sleep(0);
if (DateTime.Now.Subtract(dt).TotalSeconds > .1)
{
dt = DateTime.Now;
WriteOut(dt.ToString(" ss.ff"), false);
}
} while (!quit);
}
static void WriteOut(string msg, bool appendNewLine)
{
int inCol, inRow;
inCol = Console.CursorLeft;
inRow = Console.CursorTop;
int outLines = getMsgRowCount(outCol, msg) + (appendNewLine?1:0);
int outBottom = outRow + outLines;
if (outBottom > outHeight)
outBottom = outHeight;
if (inRow <= outBottom)
{
int scrollCount = outBottom - inRow + 1;
Console.MoveBufferArea(0, inRow, Console.BufferWidth, 1, 0, inRow + scrollCount);
inRow += scrollCount;
}
if (outRow + outLines > outHeight)
{
int scrollCount = outRow + outLines - outHeight;
Console.MoveBufferArea(0, scrollCount, Console.BufferWidth, outHeight - scrollCount, 0, 0);
outRow -= scrollCount;
Console.SetCursorPosition(outCol, outRow);
}
Console.SetCursorPosition(outCol, outRow);
if (appendNewLine)
Console.WriteLine(msg);
else
Console.Write(msg);
outCol = Console.CursorLeft;
outRow = Console.CursorTop;
Console.SetCursorPosition(inCol, inRow);
}
static int getMsgRowCount(int startCol, string msg)
{
string[] lines = msg.Split('\n');
int result = 0;
foreach (string line in lines)
{
result += (startCol + line.Length) / Console.BufferWidth;
startCol = 0;
}
return result + lines.Length - 1;
}
Personally i would use event handlers to managed a console that handles both input and outup at the same time, create a class ScreenManager or whatever, inside that class add a void RunProgram() mthod, create an event with handler and required variables for reading the input key "Console.ReadKey(bool).key".
static Consolekey newKey;
on your main program, creat an instance of your class "whatev you called it", then create a thread of that instances internal method, Thread coreThread = new Thread(delegate() {myinstance.myProgramMrthod()});
loop in your main until the threads up and running. while (!Thread.IsAlive) ;
then create the main program loop.
while (true)
{
}
then for safty, join your custom thread so the main program doesnt continue until the custom thread is closed/disposed.
customThread.Join();
you now have two threads running seperatly.
back to your class, create a switch inside your event handler method.
switch (newkey)
{
case Consolekey.enter
Console.WriteLine("enter pressed");
break;
ect, ect.
default:
Console.write(newkey); // writes character key that dont match above conditions to the screen.
break;
}
stick allyour logic inhere with how you want to handle keys.
How to use multiple modifier keys in C#
might be of some help.
inside your instance's method RunProgram() or whatev you choose to call it, after you've done whatever code you need to, create an infinite loop to check for key change.
while (true)
{
newKey = Console.ReadKey(true).Key;
if (newKey != oldKey)
{
KeyChange.Invoke();
}
}
this loop stores any key pressed and then checks to see if theres a new key, if true fires the event.
you now have the core of what your looking for, one string that loops askng for a new key, whilst the main loop is free to display whatever text you wish to display.
two fixable bugs with this that i can think of, one is "default" inside switch will print to console in caps or strings. and the other is any text added to the console is added at the cursor point so it adds to the text the user has just input.
hwoever i will, since i've just made it, how you have to manager the text been added to the console. again im using an event. i could use methods and functions throughout but events add move flexability to the program, i think.
okay so we want to be able to add text to the console, without it upsetting the input we enter. keeping the input at the bottom;
create a new delegate that has a signiture with a string argument, void delegate myDelegate(string Arg). then create an event with this delegate, call it newline, newinput, whatev you like.
the events handler will take a string argument (repersenting the console update text: what you want to insert into the console above the users input) it will grab the text the user has been entering into the console, store it, then print out the paramiter string onto the console, then print out the users input underneith.
personally i chose to create a static string at the top outside the method, initialise it to empty, cos its going to be frequently used and you dont want to be creating a new identifyer and then initialising the variable everytime the method is called, then dispose of it at the end of the method, only to recreate a new one again, and again.
call the string "input" or whatever.
in the default area of the keychange event handle add input +=newkey.
in the Consolekey.enter section console writline input then input = string.empty Or string = "".
in the event handler add some logic.
public void OnInsert(string Argument)
{
Console.CursorTop -= 1;
// moves the cursor to far left so new input overwrites the old.
// if arg string is longer, then print arg string then print input // string.
if (Argument.Length > input.Length)
{
Console.WriteLine(Argument);
Console.WriteLine(input);
}
else
{
// if the users input if longer than the argument text then print
// out the argument text, then print white spaces to overwrite the
// remaining input characters still displayed on screen.
for (int i = 0; i < input.Length;i++ )
{
if (i < Argument.Length)
{
Console.Write(Argument[i]);
}
else
{
Console.Write(' ');
}
}
Console.Write(Environment.NewLine);
Console.WriteLine(input);
}
}
hope this helps some of you, its not perfect, a quick put together test that works enough to be built on.
If you need to allow output to arrive while the user is typing I recommend sending the output to a new window. So, you could have one window that is used to start the application and then it spawns a thread to open a new console for input and then it continues to send any output messages to the original window. I think you will run in to too many resource locking issues if you try to keep everything in the same window.
This sort of thing becomes a somewhat simpler problem if you treat the server as a client/server application. Let the server have "n" connections to client admin applications that send commands and receive output. The client application could completely separate input and output, having one thread to handle input, and one to handle output.
The output thread could block if the input thread is in the middle of entering a line, and unblock when the line is either cancelled or committed.
I got my example working using Console.MoveBufferArea(), but note that this won't work on platforms other than Windows because the method is not implemented on those platforms.
With this example you would use Read() instead of Console.ReadLine() and Log(...) instead of Console.WriteLine(...) in your code.
class Program
{
static void Main(string[] args)
{
// Reader
new Thread(() =>
{
string line;
while ((line = Read()) != null)
{
//...
}
Environment.Exit(0);
}).Start();
// Writer
new Thread(() =>
{
while (true)
{
Thread.Sleep(1000);
Log("----------");
}
}).Start();
}
static int lastWriteCursorTop = 0;
static void Log(string message)
{
int messageLines = message.Length / Console.BufferWidth + 1;
int inputBufferLines = Console.CursorTop - lastWriteCursorTop + 1;
Console.MoveBufferArea(sourceLeft: 0, sourceTop: lastWriteCursorTop,
targetLeft: 0, targetTop: lastWriteCursorTop + messageLines,
sourceWidth: Console.BufferWidth, sourceHeight: inputBufferLines);
int cursorLeft = Console.CursorLeft;
Console.CursorLeft = 0;
Console.CursorTop -= inputBufferLines - 1;
Console.WriteLine(message);
lastWriteCursorTop = Console.CursorTop;
Console.CursorLeft = cursorLeft;
Console.CursorTop += inputBufferLines - 1;
}
static string Read()
{
Console.Write(">"); // optional
string line = Console.ReadLine();
lastWriteCursorTop = Console.CursorTop;
return line;
}
}
Have you tried calling OpenStandardInput, reading any input and resetting it's position, then writing to the output stream. Afterwards, you can call OpenStandardInput again and fill the data back into the stream.
There's no perfect way of accomplishing this, I think. What telnet does (at least the last version I used) was not print any input (just read the keystrokes) and simply print the output as it arrives. The alternative is to store any data that needs to be output to the console in a buffer, and only print it once the user has finished entering their command. (You could even timestamp the output, to make it more obvious.) I really can't see any better alternative here - you're inevitably going to run into problems using a synchronous I/O interface (i.e. the command line) together with asynchronous operations in the backend.