I´m uses a thread to show wait screen. User click on button process, system create a thread to show the wait screen and the process continue and i need to show the methods that the process has invoked.
public partial class Frm_Muestra_Consulta : Form
{
private void Btn_Procesa_Click(object sender, EventArgs e)
{
Cls_Generales.Iniciar_Proceso(this);//calls the warning screen processing
Cls_Consultas.Consultando(); //running process
Cls_Generales.Terminar_Proceso(this); //Close the warning screen processing
}
}
public class Cls_Generales
{
public static void Inicia_Proceso(Form _Form)
{
Pantalla_Proceso = new Thread(new
ThreadStart(Invoca_Pantalla_Proceso));
Pantalla_Proceso.Start();
_Form.Enabled = false;
}
public static void Invoca_Pantalla_Proceso()
{ Application.Run(new Frm_Procesando()); }
public static void Termina_Proceso(Form _Form)
{ Pantalla_Proceso.Abort(); }
}
public class Cls_Consultas
{
public static DataTable Consultando()
{
//Methos to exemple
//What I want is to tell the user when the system enters and
//leaves this method
Limpiar_Tabla();
Calcular_Espacio(); //and next
return Realizar_Consulta(); //and next
}
}
How do I make the yarn see or read these methods?
Related
I've got a WPF RichTextBox that I'd like to get working as a log output for the app.
I have a static class Log with method to write to the WPF RTB. Of course, this doesnt work when a background thread call the method.
I've tried using BeginInvoke, which works until the app gets closed throwing an error 'System.Windows.Application.Current.get returned null'
What is the proper approach to updating WPF RichText from other threads. And further, I dont think this background thread is disposing properly, any recommendations?
public partial class MainWindow : Window
{
Worker worker = new Worker();
public MainWindow()
{
InitializeComponent();
Log.rtb_control = rtbLog; // pass RTB ref to Log
worker.Start();
}
}
public static class Log
{
public static RichTextBox rtb_Control;
public static void Add(string Text)
{
App.Current.Dispatcher.BeginInvoke((Action)(() =>
{
rtb_Control.AppendText($"{Text}\r");
}
}
}
public class Worker
{
bool _Enabled = false;
public Worker()
{
_Manager = new Thread(new ThreadStart(Thread_Manager));
_Manager.Start();
}
public void Start()
{
_Enabled = true;
}
void Thread_Manager()
{
while(true)
{
if(_Enabled) { Log.Add("Inside Thread"); }
Thread.Sleep(10000);
}
}
}
I have no clue if the thing I want to do has a name or not.
The "Master/Slave locking system" is sadly the best wording I could come up with.
Now to the problem I have...
Imagine you have the following class:
public class Foo
{
public void Master()
{
}
public void Slave1()
{
}
public void Slave2()
{
}
}
What I desire is that the slaves methods (Slave1, Slave2) can run parallel in a multi-threading scenario, but when the master (Master) method is called the slaves method shall be blocked from executing while it is executing, additional all currently running slave methods shall run to completion upon entering the master method.
Something like this (with comments):
public class Foo
{
public void Master()
{
//block slaves from executing
//wait for slaves to finish
//do code...
//unblock slaves
}
public void Slave1()
{
//if blocked by master wait, if not execute
//if currently running when entering master method, let it finish
}
public void Slave2()
{
//if blocked by master wait, if not execute
//if currently running when entering master method, let it finish
}
}
I know I could use lock on all 3 methods but than the Slave1 methods will block each other and thats not what I desire.
public class Foo
{
private readonly object _syncLock = new object();
public void Master()
{
lock (_syncLock) //blocks Slave1, Slave2
{
//run code...
}
}
public void Slave1()
{
lock (_syncLock) //blocks Slave2, Master - dont want that
{
//run code...
}
}
public void Slave2()
{
lock (_syncLock) //blocks Slave1, Master - dont want that
{
//run code...
}
}
}
If possible I would like to have the solution inside this class and not some outside "if you call the methods that way it will do it", the mentioned methods can fire at anytime in a non-ordered way and each method can run muliple times.
If I understand you right, you want to put
Exclusive (Write) lock on Master() (no SlaveN can run)
Shared (Read) lock on each Slave (you can run another SlaveN, but not Master)
If it's your case, please, have a look at ReaderWriterLockSlim:
public class Foo {
private readonly ReaderWriterLockSlim _syncLock = new ReaderWriterLockSlim();
public void Master() {
// Exclusive (write) lock: only Master allowed to run
_syncLock.EnterWriteLock();
try {
//run code...
}
finally {
_syncLock.ExitWriteLock();
}
}
public void Slave1() {
// Read lock: you can run Slave2 (with another Read lock), but not Master
_syncLock.EnterReadLock();
try {
//run code...
}
finally {
_syncLock.ExitReadLock();
}
}
public void Slave2() {
// Read lock: you can run Slave1 (with another Read lock), but not Master
_syncLock.EnterReadLock();
try {
//run code...
}
finally {
_syncLock.ExitReadLock();
}
}
}
I have a windows form application which is supposed to show a splash screen with a label field that I want to update as the main form (called welcome.cs) loads in the background. The splash screen shows & hides just fine, but the label doesn't update.
I've done a lot of research but haven't quite found the solution.
Program.cs
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (new SingleGlobalInstance(1000))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen splashscreen = new SplashScreen();
splashscreen.ShowSplashScreen();
Welcome welcome = new Welcome(splashscreen); //Takes some time to load
splashscreen.CloseForm();
Application.Run(welcome);
}
}
Splashscreen.cs
public partial class SplashScreen : Form
{
//Delegate for cross thread call to close
private delegate void CloseDelegate();
private delegate void UpdateStatusDelegate(string status);
private static SplashScreen splashScreen;
private Thread thread = null;
public SplashScreen()
{
InitializeComponent();
}
public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashScreen != null)
return;
thread = new Thread(ShowForm);
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
static private void ShowForm()
{
splashScreen = new SplashScreen();
Application.Run(splashScreen);
}
public void CloseForm()
{
splashScreen.Invoke(new CloseDelegate(CloseFormInternal));
}
static private void CloseFormInternal()
{
splashScreen.Close();
}
public void UpdateStatus(string status)
{
splashScreen.Invoke(new UpdateStatusDelegate(UpdateStatusInternal), status);
}
private void UpdateStatusInternal (string status)
{
if (splashScreen != null && splashScreen.IsHandleCreated)
{
lblStatus.Text = status;
}
}
}
Welcome.cs
public Welcome(Splashscreen splashscreen)
{
InitializeComponent();
//Code to log the user into the system
splashScreen.UpdateStatus("Logging in...");
//my expectation is that UpdateStatus call will update the label displayed on the splash screen but it doesn't.
//Do more stuff.....
}
Does it have something to do with multi-threading or is it because im creating a new instance of splashscreen in welcome.cs before calling UpdateStatus? How would I get around this?
You could do the following
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
// Creates the Splash
splash = new FrmSplash();
//Opens the Splash in a new Thread, this way any gifs, progress bars, lablels changes will work because the main thread isnt blocked
var t = Task.Factory.StartNew(() =>
{
splash.ShowDialog();
});
while (!splash.Created) // wait the splash screen form load process
System.Threading.Thread.Sleep(300);
UpdateSplashMessage("Loading the program... Please wait");
// Some slow initialization code.
// ...
//Close splash screen
CloseSplash();
Application.Run(args);
}
static void CloseSplash()
{
splash.Invoke(new MethodInvoker(() =>
{
splash.Close(); // Closes the splash that is running in the other thread
}));
}
static void UpdateSplashMessage(string msg)
{
splash.Invoke(new MethodInvoker(() =>
{
splash.AtualizarMensagem(msg);
}));
}
Note that you will need to create a method called AtualizarMensagem(string str) in your splash screen form, like this
public void AtualizarMensagem(string novaMsg)
{
lblCarregando.Text = novaMsg;
}
I have this code in my "useful snnipets" folder, it always works for me.
Hope this helps.
I have created a simple form home and there is another file Mouse_Tracking.cs.
Mouse_Tracking.cs class is a thread class. I want to start and stop that thread using two different button click in home form.
How can I do this ?
Main form:
namespace computers
{
public partial class home : Form
{
public home()
{
InitializeComponent();
}
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
Thread thread1 = new Thread(new ThreadStart(mst.run));
thread1.Start();
}
private void btn_stop_Click(object sender, EventArgs e)
{
//Here I want to stop "thread1"
}
}
}
Computers class:
namespace computers
{
public class Mouse_Tracking
{
public void run()
{
// Some method goes here
}
}
You shouldn't kill threads from the outside. Instead, you should gently ask your thread to terminate, and in your thread you should respond to that request and return from the thread procedure.
You could use an event for that. E.g. add the following to your form class:
AutoResetEvent evtThreadShouldStop = new AutoResetEvent();
In your run method, check if the svtThreadShouldStop event is set every 0.1-1 seconds, if it’s set, return from the thread function, e.g. if( evtThreadShouldStop.WaitOne( 0 ) ) return;
And in your btn_stop_Click call evtThreadShouldStop.Set();
P.S. It’s rarely a good decision to create your own thread: creating and destroying threads is expensive. The runtime already has the thread pool you can use for your own background processing. To post your background task to a pool thread instead use e.g. ThreadPool.QueueUserWorkItem method. You can use same technique with AutoResetEvent to request task termination.
P.P.S. The name of the Mouse_Tracking class suggest you're trying to interact with mouse from the background thread? You can't do that: you can only interact with the GUI including mouse and keyboard from the GUI thread.
Here is an example of what Soonts has suggested. It's quite old-style solution but it's simple and will work fine. But there is a number of other approaches. You can use BackgroundWorker or TPL (Task class), each of which have own thread stop mechanisms.
And I believe that it's ok to create own thread without using existing thread pool if you don't need to do it too often.
public class Mouse_Tracking
{
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
public void stop()
{
_stopEvent.Set();
}
public void run()
{
while (true)
{
if (_stopEvent.WaitOne(0))
{
//Console.WriteLine("stop");
// handle stop
return;
}
//Console.WriteLine("action!");
// some actions
Thread.Sleep(1000);
}
}
}
Sometimes its quite difficult to maintain the thread. You can achieve it by using BackgroundWorker class. You will get complete demonstration on how to use it is here Stop Watch Using Background Worker. I hope it will be useful.
You could use a class like this for controlling your thread(s):
class ThreadController {
private Thread _thread;
public void Start(ThreadStart start) {
if (_thread == null || !_thread.IsAlive) {
_thread = new Thread(start);
_thread.Start();
}
}
public void Stop() {
if (_thread != null && _thread.IsAlive) {
_thread.Interrupt(); // Use _thread.Abort() instead, if your thread does not wait for events.
_thread = null;
}
}
}
Then use:
public partial class home : Form
{
public home()
{
InitializeComponent();
_thread = new ThreadController();
}
private readonly ThreadController _thread;
private void btn_start_Click(object sender, EventArgs e)
{
var mst = new Mouse_Tracking();
_thread.Start(mst.run);
}
private void btn_stop_Click(object sender, EventArgs e)
{
_thread.Stop();
}
}
I've searched and can't find a solution that helps me get text from a thread running in a separate class, back to a listbox on the form that created the thread.
Basically I have a class that holds a "test", it is called in it's own thread from a test window. What I want to be able to do is add text to a listbox on the main form to let the user know what is going on with a test. All the examples I can find on Invoke show how to do it within the same class.
Where I start the thread:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
Here is my class that actually does the work, where I need to get text back to a listbox on a separate form from.
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while( x < 100 && !aborted)
{
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
I would appreciate any one who could help me understand how to get some text back to a listbox on the same form that has the button which starts the thread.
Option 1: (Preffered) Add an event on PermeabilityTest and register on that event in your main form.
Then modify the content of your List box from within your main form.
Example:
Your main form:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
public form1()
{
// Register on the Progress event
Run_Test.Progress += Run_Test_Progress;
}
void Run_Test_Progress(string message)
{
if(listBox.InvokeRequired)
{
// Running on a different thread than the one created the control
Delegate d = new ProgressEventHandler(Run_Test_Progress);
listBox.Invoke(d, message);
}
else
{
// Running on the same thread which created the control
listBox.Items.Add(message);
}
}
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
new Delegate:
public delegate void ProgressEventHandler(string message);
Modified PermeabilityTest class:
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public event ProgressEventHandler Progress;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while (x < 100 && !aborted)
{
// Report on progress
if(Progress != null)
{
Progress("This message will appear in ListBox");
}
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
Option 2:
You could make PermeabilityTest an inner class of your main form, and by doing so, allow it to access private members of your main form.
Then you need to pass a reference of your main form to the constructor of PermeabilityTest and keep it as a member.
Option 3:
pass your list box to the constructor of PermeabilityTest
Don't forget to use Invoke on your control since you are running from a different thread.