C# Updating log textbox while running - c#

I have spent the past few days working on bot for an MMO. It runs in one big loop, with 1-2 other smaller loops inside. So far its going great. When its running it is set to update a richtextbox with what it is currently doing, just so I can easily troubleshoot later.
My problem is while its active and looping it does not auto update the textbox until it has finished everything it is doing. Which is hard when its set in an infinite loop. I would like to be able to run the bot with the main program window on the other monitor giving me updates as it goes along.
The whole program seems to freeze up and I cant interact with it at all while running. This also causes problems when I want it to stop. The only way I have of stopping it at the minute is to click Stop in visual studio.
I have tried searching around, but I have no idea what to search for. I hope I explained it well enough.
Thanks in advance.

This would be a nice read :
http://www.beingdeveloper.com/use-dispatcher-in-wpf-to-build-responsive-applications/
To summaries
You can send in a delegate fx, which is responsible for a formatter or writter. In you implemetation it would be the one which does AppendText. and make sure the Richtextbox.AppendText is within Dispatcher.Invoke()
Code Sample
class BotRand
{
//Write Event is delegate
public execute(WriteEvent writeFx)
{
//Crawl
writeFx("message");
}
}
class MainWindow : Window
{
void WriteFunc(object message, EventArgs outline)
{
Dispatcher.Invoke(new Action(() => richText.AppendText(message));
}
}
This should help you start your search more effectively.
Thanks,

Related

C# Windows Service, Timer won't tick

I have poked around here to try and find a resolved issue to help me solve my problem. Unfortunately I don't know enough about C# and Forms/Services to be able to interpret many of the answers, so I thought I'd post my issue here, in it's uniqueness, and see if I can get a sufficient answer.
I recently got an internship for a local company, learning C# and SQL to manage their shipping/inventory logistics.
I have gotten pretty good at creating windows forms with VisualStudios2017, and my knowledge of Java helps me pick up C# pretty quickly.
However, recently I was given the task of developing a Windows Service, which will run in the background, and do some repetitive task every minute or so.
Since I am familiar with the "Drag and Drop" techniques of adding features to windows forms, My supervisor suggested I use a Timer in my service, so, that's what I did, I did a "Drag and Drop" to add the timer component to my service, and renamed it "timerMainTick"
Here is My code. I want to start simple, all this code does is move to some local directory (henceforth referred to as $DIR), create a folder $DIR/GabbServiceDir, and make a text file $DIR/GabbServiceDir/AnotherTest.txt". However, every time the timer ticks, it is supposed to create (if it does not already exist) a new text document "$DIR/GabbServiceDir/Test.txt" and append the date-time to it every 2.5 seconds. This does not happen.
namespace GabbService
{
public partial class GabbService : ServiceBase
{
public string dir = "../../Users/Tyler/GabbServiceDir";
public GabbService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Directory.CreateDirectory(dir);
timerMainTick.Interval = 2500; //miliseconds = 2.5seconds
File.AppendAllText(dir + "/AnotherTest.txt","asdiofbhjasdflikjbasdf\r\n");
timerMainTick.Enabled = true;
timerMainTick.Start();
}
protected override void OnStop()
{
}
private void timerMainTick_Tick(object sender, EventArgs e)
{
timerMainTick.Enabled = false;
File.AppendAllText(dir + "/Test.txt", DateTime.Now.ToString() + "\r\n");
timerMainTick.Enabled = true;
}
}
}
And a picture of the directory and it's contents after the service was started.
This is in Powershell, in $DIR/GabbServiceDir
PS C:\Users\Tyler\GabbServiceDir> ls
Directory: C:\Users\Tyler\GabbServiceDir
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 6/23/2017 9:54 PM 72 AnotherTest.txt
PS C:\Users\Tyler\GabbServiceDir> cat .\AnotherTest.txt
asdiofbhjasdflikjbasdf
timerMainTick is Windows.Forms.Timer, and many of the solutions provided indicate to use a different kind of timer, the System.Timers.Timer.
This is all well and good, and may fix my problem, but the issue comes when trying to do something when this new type of timer ticks. When I double click the Windows.Forms.Timer in the Service Designer, it automagically writes a bunch of source, and gives me a method to begin writing code in, that magically executes when the timer ticks. I am not yet familliar with all of the magic that is going on in the backround, because I've only begun to learn C# as of the day I got this internship. I don't know what to name the methods for custom objects so that the "backround magic" will work, thus I am unable to interperate some of the solutions provided for problems similar to mine.
Perhaps someone could enlighten me.
For instance. Say I go into the Designer Source Code, and add a component
private System.Timer.Timer timerSystemTimer;
Then, in the Service source code and alter the method that was previously
private void timerMainTick_Tick(object sender, EventArgs e)
To
private void timerSystemTimer_Tick(object sender, EventArgs e)
I get an error immediately:
The more reading I do the more I see lots of event handlers being passed around and I have yet to comprehend what they do. Perhaps what I need is a link to some good literature. I am capable of looking for this on my own but I imagine many people here may have links to other bits of good literature more specific to what I want to comprehend here.
*Something I have found so far that may be useful to people in my situation:
https://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx
Error in VS - You added timerSystemTimer but did not remove timerMainTick component which still references timerMainTick_Tick as handler of it's Tick event. Compiler does not find this handler method anymore since you changed it to timerSystemTimer_Tick.
Adding different timer - Never modify designer file code. You could add a System.Timers.Timer instance to your class code, instantiate it in OnStart and provide handler for Elapsed event. Here's a sample for you.

DataGridView InvalidOperationException reentrant call to SetCurrentCellAddressCore

I've been working on this for about 8 months. It's been an annoyance more than anything until recently when I moved from a DataSet / DataTables to lists. Now the problem is a lot more prevalent (I think because the lists appear to be a LOT more efficient).
This question has been asked a few times but none of them really hit on what truly is going on (nor are any of them answered). The odd thing is I can't isolate where in my code this is causing the exception as the debugger pulls up the program.cs which only has this code:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyApp());
}
The application exception is on the Application.Run... line.
I'm using the DataGridView as a back ground processing log display. I have numerous background processes in a service that communicate back up to a winform app. The form listens for these messages (event handler / signalr) and also remove messages (like a FIFO queue) to not exceed a maximum defined amount in a list then I process the message and sort them into a BindingList[]. Then in the datagrid if I click on an item, it will display the full message in a textbox. I have multiselect turned off and again, the datagridview is read only.
Oh also, the BindingList[] is bound / rebound to the datagrid from another control so I can select which list to display in the datagridview. This is not the issue as I've isloated the issue by forcing a single specific list in the code and still have the problem.
To get this to crash, I can click on datagrid numerous times and eventually it will crash. If I really want to crash it quickly, I click on the datagridview and scroll (keyboard arrow) down and up and I can crash it in a few seconds.
I found this article (click here) on StackOverflow that describes what is going on. And in one of the comments it refers to a Microsoft Bug Report(click here) which stats this is by design! However, most are talking about manipulating the cells which I am not doing. The top message is nearly identical to what is happening to me but the programmer is using an inherited DataGridView so his solution will not work for me.
This does have to do with adding and or deleting items from the BindingList. I can get it to crash if I have either of the going on while scrolling / selecting in the DataGridView. But that code is very simple:
private void DelRow( string szTableName)
{
try
{
int nProcQueue = qdList.Queue(szTableName);
MsgQueues[nProcQueue].RemoveAt(0);
this.BeginInvoke(new MethodInvoker(Refresh_dgvDetail));
}
catch (Exception ex)
{
LogEx(ex);
}
}
and
private void AddRow(LogObject oLogObject, string szTableName)
{
try
{
int nQueueNumber = qdList.Queue(szTableName); // helper object to return queue number based off the name of the list
MsgQueues[nQueueNumber].Add(oLogObject);
this.BeginInvoke(new MethodInvoker(Refresh_dgvDetail));
}
catch (Exception ex)
{
LogEx(ex);
}
}
This really seems like a c# bug... Why MS would have this as designed is beyond me...?
Anyone know how to stop this behavior?
Grek40, you're right; I was wrong. I did the MethodInvoker for just the add; not the delete. It had to be done for both. Basically anything method that touches the datagridview needs to have MethodInvoker. This is an example of what I did:
this.Invoke((MethodInvoker)delegate { MsgQueues[nCurrentQueue].RemoveAt(0); });
Problem went away.
Set the column on the side to ReadOnly = true;

C#: Periodically update GUI based on backgroundtask

I have a GUI that is for all intents and purposes really basic. A listview, an html form, and that's really it.
I want the user to have the following behavioral ability:
1 - Click a checkbox that says "Real-time". When clicked, a background thread will run once every 10 seconds.
2 - If there is a new file created (this is easy, to observe a new file) I want an alert displayed in my main gui. Where it is displayed for now is arbitrary (in a label, for example).
The main issue is I cannot figure out how to do this in a multi-threaded example. My goal is exactly in line with multithreading: do tasks 1 and 2, without locking task 1. Meaning, while the update check is running, the user can interact with the GUI as if nothing was going on in the background.
If you need more details to better answer this please let me know.
Thanks!
Here are a couple sites I found useful for implementing a background worker when I needed to perform database operations while still allowing the GUI to be responsive:
http://msdn.microsoft.com/en-us/library/zw97wx20.aspx
http://www.codeproject.com/KB/cs/AsynchronousCodeBlocks.aspx
Use events from the thread to tell the UI that something's changed:
// Just detected that that a new file has been created
if (this.FileCreated_Event != null)
{
this.FileCreate_Event(this, new FileEventArgs(newFileName));
}
where FileCreated_Event and FileEventArgs are declared appropriately.
Then in the UI when you receive the event you have the following:
this.fileChecker.FileCreated_Event += this.FileCreated_Event;
and:
private void FileCreated_Event(object sender, TrackStatusEventArgs e)
{
if ((sender as Control).InvokeRequired)
{
(sender as Control).Invoke(action);
}
else
{
action();
}
}
where action is the thing you want to do.
Try this tutorial. At the end I'm sure you'll be able to use threads. You must be careful though, because you'll have to manage those threads which can be a daunting task. I've never met a programmer who liked to debug multiple threads...

How to run form and console at the same time with c#?

Hey I am fairly new to the c# programming language and have enjoyed my experience so far. I normally develop applications in java but a need for the win32 library has lead me to c# so far the languages seem relatively similar. however a problem I am having at the moment is a simple piece of code that can be best explained in this example
I am trying to print a piece of string to console then display the windows form then print another piece of string to console. however the result i get is first string is printed then the form is displayed, i then have to close the form before the last string is printed. the question i would like to ask is is there anyway to get this working so the second print to console is displayed immediately after the form is displayed. im guessing it has something to do with threading but I am not entirely sure how to implement this
The solution is quite simple:
Just create a Windows Forms Application (when creating the project - which you probably did) and then go to Properties (in context menu "Project", it's the last item) and set "Output type" to "Console Application". The forms will work as before and furthermore the application will now open the console too. You can then freely write to or read from the console.
static class Program
{
[STAThread]
static void Main()
{
Console.WriteLine("first string");
var form = new Form1();
form.Show();
Console.WriteLine("the second string");
Application.Run();
}
}
It sounds like you want to be able to output messages to the console while the form is being displayed, correct? The basic issue is that as long as the form is visible, there must be a message loop running, handling events for the form. The message loop is inside Application.Run, so once you call it, it won't return until the form is closed (as you discovered).
So if you want to write to the console while the form is visible, you have a couple of options. One, as you mentioned, is to use multiple threads. Let your main thread run the message loop, and start up a second thread to write to the console. But that's not necessary--you can also write to the console from within an event handler, directly or indirectly. There's nothing wrong with doing a Console.WriteLine from within a button click handler. Or you can have your button handler call a method in your Program class, and do the writing there.
As for which solution is better, it would help to know more about what you're trying to accomplish. I assume that you don't just want to write stuff to the console--what else is it that you want to do while the form is being displayed?
My suggestion would be to start with a Console application. You can always open a WinForm from a console application...which would give you exactly what you're looking for. (you might want to think about multi-threading as well.
Hey everyone thanks for your answers I made some progress with what im trying to achieve but im not sure how correct or thread safe it is here is the code i got to run
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Project1
{
class Class2
{
[STAThread]
static void Main()
{
Console.WriteLine("hello");
Class2 t = new Class2();
t.test();
Console.WriteLine("second string");
}
public void test()
{
Thread t = new Thread(new ThreadStart(StartNewStaThrea));
t.Start();
}
private void StartNewStaThrea()
{
Application.Run(new Form1());
}
}
}
pls let me know what you think of this solution
I know this is a super-old question, but I'm going to answer in hopes of karma. One interesting work-around that works well for this comes up if you're using Visual Studio (which is a fairly safe assumption). If you start a forms project in C# in Visual Studio, then make your appropriate forms, but then change the project type to a console application (by right clicking the project-->properties-->Console Application), it will still spawn your forms, but will also keep a Console open, now all you need to do is put one Console.Write statement before your form is created, and the other after, and maybe add a flush statement!
are you using form.showDialog() or form.show()?
form.showDialog() will block until the form is closed, while form.show() will not.
I would either start with a console app, and run the application from the static main function. This is from memory - I haven't had to mess with Winforms for years:
[STAThread]
static void Main()
{
Application.Run(new YourMainForm());
}
or
I would redirect Console.Out and shove that stream into a some sort of control like a text box or list box. This is a lot of code but doable... I have written this before for on-site debugging but don't have the code handy.
Why don't you just create a new windows form with multiline textbox and dock it to the form, set BackColor as Black ForeColor as White and create a public method to send text to that textBox.
If your aim is a one Form application this works pretty much brilliantly.

.NET Windows Service with timer stops responding

I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:
public partial class ArchiveService : ServiceBase
{
Timer tickTack;
int interval = 10;
...
protected override void OnStart(string[] args)
{
tickTack = new Timer(1000 * interval);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
...
}
}
It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.
I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.
The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).
Does somebody experienced this behavior? What can be wrong?
Edit:
I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.
Edit:
I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".
unhandled exceptions in timers are swallowed, and they silently kill the timer
wrap the body of your timer code in a try-catch block
I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.
To your other points...
I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.
Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.
http://support.microsoft.com/kb/842793
This is a known bug that has resurfaced in the Framework more than once.
The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.
Your mileage may vary, so verify with your combination of OS/Framework bits.
Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:
void TimeLoop(object arg)
{
stopTimer();
//Do some stuff
startTimer();
}
You could also lock(...) your main loop to protect against reentrancy.
Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
CheckForRecycle();
// ... actual code
}
private void CheckForRecycle()
{
lock(someLock) {
if(++tickCount > MAX_TICKS) {
tickCount = 0;
tickTack.Stop();
// re-create timer
tickTack = new Timer(...);
tickTack.Elapsed += ...
tickTack.Start();
}
}
}
You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.
Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.
I have made exactly the same as you in a few projects but have not had the problem.
Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?

Categories