I am currently working on a user form and having issues getting any sort of delay to work as I intend it to. I have the program check through multiple text boxes and display a message in a listbox. The program sets the background color of the text box to match the color of the message. This all works great, but all the messages are displayed at once. I would like to pause between each message before displaying the next one. I have tried using a timer, which would wait prior to displaying the first message, but then would display all messages at once after the timer expired. I tried using a delay, but again the messages would all appear at once. I also tried sleep, but since this is all one thread it will sleep the entire thread and then wake and display all messages at once. No matter what I attempt the messages all display simultaneously.
The messages are being called from a void I created:
public void writeMessage(TextBox messageBox, string message, Color messageColor)
{
Brush colorBrush = new SolidColorBrush(messageColor);
messageBox.Background = colorBrush;
if (statusList.Items.Count == 0)
{
list = new List<listColor>();
list.Add(new listColor(message, new SolidColorBrush(messageColor)));
}
else
{
list = ((IEnumerable<listColor>)statusList.ItemsSource).ToList();
if (!list[list.Count - 1].StatusItem.Equals(message))
{
list.Add(new listColor(message, new SolidColorBrush(messageColor)));
}
}
statusList.ItemsSource = list;
statusList.Items.Refresh();
statusList.ScrollIntoView(statusList.Items[statusList.Items.Count - 1]);
}
On my button click I call the above void multiple times i.e.
writeMessage(textBox1, "Error!", Colors.Red);
writeMessage(textBox2, "Warning!", Colors.Blue);
I tried adding the timer and delay into the writeMessage void, but it would not space out the messages. Anyone have any ideas or tips on how I could add a 2 second pause in the writeMessage void such that each time it is called it will wait for 2 seconds before continuing?
It's not entirely clear what's going on in your user interface, but... if you're on .NET 4.5, you should just be able to do something like this:
writeMessage(textBox1, "Error!", Colors.Red);
await Task.Delay(1000);
writeMessage(textBox2, "Warning!", Colors.Blue);
The containing method will have to be marked async.
You may also benefit from following the MVVM pattern here. Consider looking into how to use bindings, observable collections, and data templates.
Related
I need to write code in C# that sends data from Serial to an Arduino every 2 seconds.
This is what I tried to do:
Thread sender = new Thread(voidSender);
public static void voidSender() {
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
}
In your example you are starting a thread running through the defined method, sending a single message. To send the message multiple times you need to add a loop to this method like
public void voidSender()
{
//Send forever
while(true)
{
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
}
}
However, periodically events are typically done by using a timer. Simply initialize a timer like
System.Timers.Timer sendMessageTimer = new System.Timers.Timer(2000);
sendMessageTimer.Elapsed += OnSend;
sendMessageTimer.AutoReset = true;
sendMessageTimer.Enabled = true;
Inside the elapsed handler you can send the message like
private void OnSend(Object source, ElapsedEventArgs e)
{
serialArduino.WriteLine("Test");
}
Honestly I don't why you would mix open source platform such as Arduino with C# .net if its not running on core, but that's your concern not mine, I personally wouldn't do that.
if you want to send command every two seconds, I would advise you to use windows scheduler that's integrated in every windows system, however you can implement a clock on your own very easy, still why would you need to put such heavy load of 2 seconds timeframe when it will be almost notable by ordinary user. If you don't want to use clock based system you can use this modified example however it may throw stackoverflow exception sometime since its recursion and you must aways stay away from them if you plan to use this on the long run.
//First sorry for reusing your code but I am writing from my smartphone and
//I am kind of lazy here is quick modification that would work but not the most clever way around
Thread sender = new Thread(voidSender);
public static void voidSender()
{
start:
serialArduino.WriteLine("Test");
Thread.Sleep(2000);
goto start;
}
I have a program that can read and write on serial, GPIB, USB, and Ethernet. It has a tab for each method of communication with a textbox inside that displays communication on the port. One of the tabs is listed as All Comms and that text box has data from all communication methods. I am currently working on the serial port portion of the code and my program keeps freezing. Half the time I run my code it functions without issue writing to both tabs. The other half it freezes up when it tries to write to the text box inside the tab that is not selected(found by stepping through the code a line at a time).
I pulled the text boxes outside the tab control and this fixes the freezing issue. When the program freezes it does not display an error message and does not crash so no crash report(left it running over the weekend and it never finished crashing).
I would think that I need to select the other tab and then write to it, but why would the code work correctly half the time I run it?
Image of the program
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
rxString = rxString + serialPort1.ReadExisting();
if (rxString == "\b")
{
//Removes 1 character when backspace is the key pressed
rxSerialTextBox.ReadOnly = false;
rxSerialTextBox.Select(rxSerialTextBox.TextLength - 1, rxSerialTextBox.TextLength);
rxSerialTextBox.SelectedText = String.Empty;
rxSerialTextBox.ReadOnly = true;
rxString = "";
}
while (rxString.Length != 0)
{
try
{
while (rxString.Length != 0)
{
if (rxString.IndexOf("\r\n") == 0)
{
//Adds a newline when newline is the next characters in the string
rxString = rxString.Substring(rxString.IndexOf("\r\n") + 2);
rxAllCommsTextBox.AppendText(Environment.NewLine);
rxSerialTextBox.AppendText(Environment.NewLine);
}
//Adds a new character to the text box
rxAllCommsTextBox.AppendText(rxString.Substring(0, 1));
rxSerialTextBox.AppendText(rxString.Substring(0, 1));
rxString = rxString.Substring(1, rxString.Length - 1);
}
}
catch
{
//rxString = "";
}
}
}
A quck look at the SerialPort.DataReceived event documentation brings into attention the following Remarks section paragraph:
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
According to this, your code that touches UI elements (text boxes) inside that event handler is incorrect. What the documentation doesn't say is that when you do so, the behavior is undefined - sometimes it may work, another time hang, yet another time throw exception.
So, instead of asking why your incorrect code sometimes work, you'd better concentrate on making it correct, and only then if something is not working, ask why and seek for a solution.
P.S. I'm not going to address how the concrete issue can be solved - there are a tons of posts, explanations and examples of how to marshal the calls to the UI thread, and in that regard there is nothing special in your case.
It was a little confusing your question ...
you can try, it is understood correctly, try to keep the value you want to assign the memory context, and assign the value based on another type of iteration.
At the moment the application freezes, which shows the breakpoint? The expected behavior does it work?
I would try a configuration object, such as a list, with various configurations, and certain state, the amount you need to pass the list to the tabcontrol. Obviously, it needs to check what's not working and why is not ...
I have a long running method that must run on UI thread. (Devex - gridView.CopyToClipboard())
I do not need the UI to be responsive while copying and I added a splash screen so the user isn't bored out of his mind.
When I run this program all is well.
Trouble starts when I run a different program which in turn starts a new process and runs the program on it.
After a few seconds of copying the title reads (Not Responding) and the mouse cursor shows busy, it of course clears up within a few seconds but I'd like to get rid of it since it gives the user the misconstrued feeling that the program is faulty.
Is there any way to set the "Time out" of a process I create?
EDIT:
The main program calls the following code:
fillsProcess = new Process();
fillsProcess.StartInfo.FileName = Application.ExecutablePath;
fillsProcess.Start();
In the fillsProcess, when a certain button is clicked the following code is called:
gridViewToCopy.CopyToClipboard();
This line of code takes a while to process and after a few seconds the window of the fillsProcess looks unresponsive since this method runs on the UI thread..
EDIT The 2nd:
Apparently (and really quite understandably)
gridViewToCopy.CopyToClipboard();
Is not the only method causing this problem. Many Devex methods have to run on UI thread (e.g. Sorting of data, Filtering of data)
So thanks to anyone who offered specific solution (that either worked or didn't) but my original question pops right back up again:
Is there any way to change the time-out time or somehow control the whole "Not Responding" fiasco?
You can use DisableProcessWindowsGhosting win32 function:
[DllImport("user32.dll")]
public static extern void DisableProcessWindowsGhosting();
This actually doesn't prevent the window from freezing, but prevents the "Not Respongind" text in the title.
I am afraid the simplest solution is to make your own CopyToClipboard() where you in your for loop, every now and then, do an Application.DoEvents, which keeps the ui thread responsive.
I guess most licenses of DevExpress have the source code available, so you can probably copy paste most if it.
Since you know the data you can probably make a much simpler procedure than the generic that DevExpress uses.
like this:
const int feedbackinterval = 1000;
private void btnCopy_Click(object sender, EventArgs e)
{
StringBuilder txt2CB = new StringBuilder();
int[] rows = gridView1.GetSelectedRows();
if (rows == null) return;
for (int n = 0; n < rows.Length; n++)
{
if ((n % feedbackinterval) == 0) Application.DoEvents();
if (!gridView1.IsGroupRow(rows[n]))
{
var item = gridView1.GetRow(rows[n]) as vWorkOrder;
txt2CB.AppendLine(String.Format("{0}\t{1}\t{2}",
item.GroupCode, item.GroupDesc, item.note_no??0));
}
}
Clipboard.SetText(txt2CB.ToString());
}
This is because you call a long running method synchronously in your main application thread. As your applicaton is busy it does not respond to messages from windows and is marked as (Not Responding) until finished.
To handle this do your copying asynchronously e.g. using a Task as one simplest solution.
Task task = new Task(() =>
{
gridView.Enabled = false;
gridView.CopyToClipboard();
gridView.Enabled = true;
});
task.Start();
Disable your grid so nobody can change values in the GUI.
The rest of your application remains responsive (may has side effects!).
You could start the process hidden and then check if responding and bring it back into view when complete....your splash screen would show its still "responding".
Process proc = new Process();
proc.StartInfo.FileName = "<Your Program>.exe"
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Edit:
You could also create a Timer event watching the other process and roll your own timeout logic
DateTime dStartTime = DateTime.Now;
TimeSpan span = new TimeSpan(0, 0, 0);
int timeout = 30; //30 seconds
private void timer1_Tick(Object myObject, EventArgs myEventArgs)
{
while (span.Seconds < timeout)
{
Process[] processList = Process.GetProcessesByName("<YourProcess.exe>");
if (processList.Length == 0)
{
//process completed
timer1.Stop();
break;
}
span = DateTime.Now.Subtract(dStartTime);
}
if (span.Seconds > timeout)
{
Process[] processList = Process.GetProcessesByName("<YourProcess.exe>");
//Give it one last chance to complete
if (processList.Length != 0)
{
//process not completed
foreach (Process p in processList)
{
p.Kill();
}
}
timer1.Stop();
}
}
Edit2
You could use pInvoke "ShowWindow" to accomplish hiding and showing the window too after its started
private const int SW_HIDE = 0x00;
private const int SW_SHOW = 0x05;
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
There are several possible approaches
Hide the main form for the period of the operation
Somehow clone/serialize the control and pass it to a thread with another UI dispatcher
Get the selected cells via gridView.GetSelectedCells() and then put their contents to the clipboard asynchronously
It would be more helpful if you've uploaded the GridView library somewhere, so that we could look inside.
I'm unclear whether your user needs to see the screen that is "unresponsive". If it unnecessary, you might try letting the application run in the background after the main thread for this app is closed; or you may minimize the app.
If it is necessary to see the application and for it to appear to be working, can you segment your "copy to clipboard" function such that is is threaded and takes in either an array or the gridview and an index range. The advantage to this is that your main thread on your subordinate process would never hang. The disadvantage is that people don't like to work with threading and delegates in C#.
Okay, the 'Not Responding' and window artifacting you've described are just symptoms of running a long term activity on your UI thread. The UI thread is blocked, so the UI is frozen. There is no avoiding this. To be honest, it's just 'lucky' that your application appears as responsive as it does.
As far as I can see every workaround that has been described here is just a hack to fudge the fact that your UI thread is frozen. Don't do this. Fix your program so the UI thread isn't frozen.
Ask yourself: do my users really need to copy all the rows from this view? Can the data be filtered in some way to limit the rows? If not, there is a property called MaxRowCopyCount which limits the number of rows that are copied - can this be leveraged without breaking your workflow?
Finally, if all else fails, is there some other medium you can use (perhaps an intermediate file), to which data can be copied on a background thread?
The timeout, documented in IsHungAppWindow, cannot be changed. Don't use global state to manage a local problem.
You have to optimize the part that causes unresponsiveness. For example use caching, virtual grid (DevExpress calls it "server mode"), paging, delegate the sorting to an ibindinglistview filter that does a database query (uses database index) instead of in-memory sorting (no indexing) or implement IAsyncOperation on your clipboard data so you would only need to populate the data when the user does a paste.
I really need your help since I have a frustrating problem. I'm downloading data in my periodic agent (OnInvoke). Works fine but every night the web site I download data from has no data to download. If that happens I want the live tile to remain as it is (instead of beeing empty) with the current data and not get updated. Then one or two hours later when there is data to download and parse the update should continue.
I have tried this but when NotifyComplete is called the the code after still gets executed. Isn't NotifyComplete supposed to stop the rest of the code to be executed?
MatchCollection matchesMyData = rxMyData.Matches(strHTML);
foreach (Match matchMyData in matchesMyData)
{
GroupCollection groupsMyData = matchMyData.Groups;
//Code for handling downloaded data
}
if (matchesMyData.Count < 1)
{
ShellToast toast = new ShellToast();
toast.Title = "No update: ";
toast.Content = "Webservice returned no data";
toast.Show();
NotifyComplete();
}
I also tried the following peice of code but that stopped my background task and I had to start my app again to re-enable it. Why?
ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileID=2"));
if (TileToFind != null && intCount > 0)
{
//Update the live tile
}
So, when no data gets parsed the tile should remain as it is and an hour or two later when data gets downloaded everything should be back to normal with thetile beeing updated.
Please help, since this is a show stopper right now. Thanks in advance.
Calling NotifyComplete() will not stop the code after the method call being executed, it just lets the OS know that you are finished. The OS should abort the thread but there may be time for a few more lines of code to run (the documentation isn't clear on whether the thread that calls NotifyComplete will be aborted immediately).
If you add a return statement after the call to NotifyComplete then the tile shouldn't be updated.
I'm trying to write some sort of a log to an algorithm. That is, while the simulation is running, I want to add a text to the log, saying what is going on in the simulation (at let's say 2 seconds time from the previous add).
I've tried using
Thread.Sleep(2000);
but this just makes the entire text appear in the log at the end of the simulation after number_of_loops x 2 seconds.
What else can I try?
Use a timer control, see this for a walkthrough. Put your updating code into the tick method.
This should do this:
public void updateMessage()
{
DateTime start = DateTime.Now;
while (DateTime.Now.Subtract(start).Seconds < 15)
{
//do your update here
textbox.text+="STATUS";
}
}
Thread threadUpdating=new Thread(new ThreadStart(updateMessage));;
threadUpdating.Start();