I'm trying to make a simple clock program with threads. In Form1 I want to create a new thread that's in ThreadProc(), take time, and sent back to Form1 send() method that will replace the text in label.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ThreadProc tP = new ThreadProc();
Thread t = new Thread(tP.threadP);
t.Start();
}
public void send(Object obj)
{
string time;
try
{
time = (string)obj;
}
catch (InvalidCastException)
{
time = " ";
}
if (label1.InvokeRequired)
this.Invoke((MethodInvoker)delegate () { label1.Text = time; });
else
label1.Text = time;
}
}
internal class ThreadProc
{
public void threadP()
{
Form1 form1 = new Form1();
DateTime dateTime;
do
{
dateTime = DateTime.Now;
string time = dateTime.ToString();
Thread t = new Thread(() => form1.send(time));
t.Start();
Thread.Sleep(500);
} while (true);
}
}
It ends up in infinite loop of Form1() -> threadP() -> Form1()... but without
Form1 form1 = new Form1();
I can't call send() in
Thread t = new Thread(() => form1.send(time));
The threadP() has to be in their own class and send() has to be in Form1 class.
Pass a reference to your form to the thread. You can then access it from there.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ThreadProc tP = new ThreadProc();
Thread t = new Thread(tP.threadP);
// Automatically end thread when application ends
t.IsBackground = true;
// Pass reference to this form to thread
t.Start(this);
}
public void Send(string time)
{
if (Visible) // Check form wasn't closed
{
if (label1.InvokeRequired)
this.Invoke((MethodInvoker)delegate () { label1.Text = time; });
else
label1.Text = time;
}
}
}
internal class ThreadProc
{
public void threadP(object data)
{
// Get Form1 reference from start parameter
Form1 form1 = data as Form1;
DateTime dateTime;
do
{
dateTime = DateTime.Now;
string time = dateTime.ToString();
form1.Send(time);
Thread.Sleep(500);
} while (true);
}
}
Note that there are better designs to re-use the thread like passing an interface instead of the concrete Form1 class. But this is just a simple example.
When a Form and a background thread are so closely bound together, you usually use a BackgroundWorker instead of threads.
Related
public static void Monitor0()
{
bool ToMineOrNot = Backend.ToMineOrNot;
while (ToMineOrNot)
{
Form1 temp = new Form1();
Form1.NonStaticDelegate = new Action(temp.setHashRate);
Form1.NonStaticDelegate();
Backend.hps = 0;
Thread.Sleep(1000);
}
if (ToMineOrNot == false)
{
}
}
public void setHashRate()
{
hashrate.Text = Backend.hps.ToString();
}
I have to get the Static Void to call the non Static Void, i have to have Monitor0 Static because it has to be Run in a Thread, and setHashRate() has to be Non-static to edit the label (It's a Windows form):
Thread thread = new Thread(Monitor0);
thread.Start();
Does anybody know how i could Do that? and I cant just do this because the label won't be changed:
Form1 form = new Form();
form.label1.Text = "text"
I have a problem with using nancyfx in my winform application (I make a winform app and use a nancyfx inside the application) So i can use some API url to make change in the winform without additional server or services (because i attached the nancy in the winform apps)
Here is my Form1.cs
public partial class Form1 : Form
{
public Form1(bool test)
{
InitializeComponent();
textBox1.Text += "Apps Method "+ Environment.NewLine;
}
public bool startTestAPI()
{
textBox1.Text += "Api Worked" + Environment.NewLine);
}
private void button2_Click(object sender, EventArgs e)
{
HostingAPI s = new HostingAPI();
s.Start();
textBox1.Text += "Api Running" + Environment.NewLine);
}
}
public class ModuleCDM : NancyModule
{
public ModuleCDM()
{
try
{
Thread th2 = Thread.CurrentThread;
Get["/Start"] = parameters =>
{
Form1 form = new Form1(false);
Thread testthread = Form1.curthread;
bool res = form.startTestAPI();
if (res == true)
{
var feeds = new string[] { "Success" };
return Response.AsJson(feeds);
}
else
{
var feeds = new string[] { "Failed" };
return Response.AsJson(feeds);
}
};
}
}
}
and this is my HostingAPI.cs
public class HostingAPI
{
private NancyHost hostNancy;
private string hostUrl;
public void Start()
{
hostUrl = ConfigModule.ModuleAddress;
if (hostUrl == null) hostUrl = "http://localhost:5005";
hostNancy = new NancyHost(new Uri(hostUrl));
hostNancy.Start();
}
public void Stop()
{
hostNancy.Stop();
}
}
And it successfully run without error, but when i call api (localhost:5005/Start) the textbox in winform apps not add the text i wanted ("Api Worked"). I noticed it is because Nancyfx create another thread when there is API call, and i can use invoke/begininvoke because !invokerequired always comes with value false. So how can i access the main thread or maybe another solution to update the UI when i call the API.
Thanks
You have 2 issues in here.
You start host api service from Form1 instance then within Nancy Module you create a different Form1 instance which is invisible and you try to do access certain methods within that class
Cross thread issue as you rightfully guessed . You are trying to write from another thread context than the UI thread
Look at the code at below to achieve this. Bear in mind that you can create Singleton Form or find another way to access the instance of Form1
public class HostingAPI
{
private NancyHost hostNancy;
private string hostUrl;
public HostingAPI()
{
}
public void Start()
{
var hostConfig = new HostConfiguration
{
UrlReservations = new UrlReservations
{
CreateAutomatically = true
},
};
//hostUrl = ConfigModule.ModuleAddress;
if (hostUrl == null) hostUrl = "http://localhost:5005";
hostNancy = new NancyHost(hostConfig,new Uri(hostUrl));
hostNancy.Start();
}
public void Stop()
{
hostNancy.Stop();
}
}
public partial class Form1 : Form
{
delegate void SetTextCallback(string text);
public static Form1 Instance;
public Form1(bool test)
{
InitializeComponent();
textBox1.Text += "Apps Method " + Environment.NewLine;
Instance = this;
}
private void button1_Click(object sender, EventArgs e)
{
HostingAPI s = new HostingAPI();
s.Start();
textBox1.Text += "Api Running" + Environment.NewLine;
}
public void startTestAPI()
{
SetText("Api Worked" + Environment.NewLine);
}
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text += text;
}
}
}
public class ModuleCDM : NancyModule
{
public ModuleCDM()
{
try
{
Thread th2 = Thread.CurrentThread;
Get["/Start"] = parameters =>
{
var form1 = Form1.Instance;
form1.startTestAPI();
var feeds = new[] {"Success"};
return Response.AsJson(feeds);
};
}
catch
{
}
}
}
I've found that example (Communicate between two windows forms in C#) that works fine but not when the two forms are in different thread.
I've got an "System.NullReferenceException" at line 20 in MainForm (this.splashy.LabelText = i;)
The point of this script is to modified the width of the progressBar in the splashscreen when MainForm is doing his job.
Thanks in advance!
Here are the two c# classes and program file:
//Program.cs
using System;
using System.Threading;
using System.Windows.Forms;
namespace GIS
{
static class Program
{
public static SplashScreen splashy = null;
/// <summary>
/// Point d'entrée principal de l'application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Thread splashThread = new Thread(new ThreadStart(
delegate
{
//SplashScreen splashy = new SplashScreen();
splashy = new SplashScreen();
Application.Run(splashy);
}
));
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start();
//run form - time taking operation
MainForm mainForm = new MainForm(splashy);
mainForm.Load += new EventHandler(mainForm_Load);
Application.Run(mainForm);
}
static void mainForm_Load(object sender, EventArgs e)
{
//close splash
if (splashy == null)
{
return;
}
splashy.Invoke(new Action(splashy.Close));
splashy.Dispose();
splashy = null;
}
}
}
//SplashScreen.cs
using System;
using System.Windows.Forms;
namespace GIS
{
public partial class SplashScreen : Form
{
public SplashScreen()
{
InitializeComponent();
}
public int LabelText
{
get
{
return rectangleShape1.Width;
}
set
{
rectangleShape1.Width = value;
}
}
}
}
//MainForm.cs
using System.Threading;
using System.Windows.Forms;
namespace GIS
{
public partial class MainForm : Form
{
private SplashScreen splashy = null;
public MainForm(Form callingForm)
{
splashy = callingForm as SplashScreen;
InitializeComponent();
doWork();
}
private void doWork()
{
for(int i = 0; i < 100; i++)
{
this.splashy.LabelText = i;
Thread.Sleep(10);
}
}
}
}
You need to invoke the SplashScreen to change it's value from an other thread like
this.splashy.Invoke((MethodInvoker) delegate { this.splashy.LabelText = "Requested" + repeats + "Times"; });
Note that the constructor
splashy = callingForm as SplashScreen;
allows splashy to be null - this causes your current NullReferenceException.
This problem is locaed in this snipped:
Thread splashThread = new Thread(new ThreadStart(
delegate
{
splashy = new SplashScreen();
Application.Run(splashy);
}
));
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start();
//run form - time taking operation
MainForm mainForm = new MainForm(splashy);
The new thread you are start is not fast enought to create the instance of SplashScreen before you pass it. The result - you are passing null.
Fix it by create the splashy before your thread starts:
splashy = new SplashScreen();
Thread splashThread = new Thread(new ThreadStart(
delegate
{
Application.Run(splashy);
}
I've been trying to learn delegates.I just created a button,label and checkbox. If I click checkbox, the time format changes. If i click the button , i print the date accordingly. However when trying to use asynchromous delegate i.e., to use another thread, i am stuck with an error
public delegate void AsyncDelegate(bool seconds);
public partial class Form1 : Form
{
AsyncDelegate ad;
TimeZ t = new TimeZ();
public Form1()
{
InitializeComponent();
}
private void btn_async_Click(object sender, EventArgs e)
{
ad = new AsyncDelegate(t.GetTime);
AsyncCallback acb = new AsyncCallback(CB);
if (chk_sec.Checked)
{
ad.BeginInvoke(true, acb, null);
}
else
ad.BeginInvoke(false, acb, null);
}
public void CB(IAsyncResult ar)
{
t.Tim = ar.ToString();
ad.EndInvoke(ar);
lbl_time.Text = t.Tim;
}
and in another class library i get Timez used above. I add a reference of it in the project
public class TimeZ
{
private string tim;
public string Tim
{
get
{
return tim;
}
set
{
tim = value;
}
}
public string GetTime(bool seconds)
{
if (seconds)
{
return DateTime.Now.ToLongTimeString();
}
else
return DateTime.Now.ToShortTimeString();
}
}
However i get this error when i run the program:
Cross-thread operation not valid: Control 'lbl_time' accessed from a thread other than
the thread it was created on.
Can u help me out on how to solve this?
You cannot access forms and controls properties and methods from a thread that is not the form thread.
In windows, each window is bound to the thread that created it.
You can do that only with Control.BeginInvoke or the more useful System.Threading.SynchronizationContext class.
See http://msdn.microsoft.com/it-it/library/system.threading.synchronizationcontext(v=vs.95).aspx
See http://msdn.microsoft.com/it-it/library/0b1bf3y3(v=vs.80).aspx
It means, you have to post through synchronization context for example another async delegate in form thread.
public partial class Form1 : Form
{
AsyncDelegate ad;
TimeZ t = new TimeZ();
// Our synchronization context
SynchronizationContext syncContext;
public Form1()
{
InitializeComponent();
// Initialize the synchronization context field
syncContext = SynchronizationContext.Current;
}
private void btn_async_Click(object sender, EventArgs e)
{
ad = new AsyncDelegate(t.GetTime);
AsyncCallback acb = new AsyncCallback(CB);
if (chk_sec.Checked)
{
ad.BeginInvoke(true, acb, null);
}
else
{
ad.BeginInvoke(false, acb, null);
}
}
public void CB(IAsyncResult ar)
{
// this will be executed in another thread
t.Tim = ar.ToString(); // ar.ToString()???? this will not give you the time for sure! why?
ad.EndInvoke(ar);
syncContext.Post(delegate(object state)
{
// This will be executed again in form thread
lbl_time.Text = t.Tim;
}, null);
}
I don't know why you need an asynchronous callback to print time however :) really don't know why, thinking it is just some test code.
I have a method that creates a bound with a windows form and also sents to that window form a parameter. I would like to create a thread to that window form. How can I do it?
public Send_to_windowForm(string name_form, string value_for_labellBox)
{
thread t = new thread(new threadStart (form(value_for_labelBox)).Start();
Application.Run(new form(value_for_labelBox));
form.text=name_form;
}
it's not working. I don't think it's correct. How can I do it? And one more question: how can i handleall the form application that the thread opens? I would like to handle all the forms because in a specific moment i want to add a new value to one of the forms opened on the desktop.
THX
You need to do something like this:
namespace UIThreadMarshalling {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var tt = new ThreadTest();
ThreadStart ts = new ThreadStart(tt.StartUiThread);
Thread t = new Thread(ts);
t.Name = "UI Thread";
t.Start();
Thread.Sleep(new TimeSpan(0, 0, 10));
}
}
public class ThreadTest {
Form _form;
public ThreadTest() {
}
public void StartUiThread()
{
using (Form1 _form = new Form1())
{
Application.Run(_form);
}
}
}
}