i have app with gui
I put function checkproxy() in Form1.cs it works correctly and i want move function checkproxy() to other class but if i put checkproxy() in other class it will error with Invoke and richTextBox3
namespace test3
{
public partial class Form1 : Form
{
public bool continueThreads = false;
string[] proxyList = null;
List<Thread> threadList = new List<Thread>();
int proxynum = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int n = (int)numericUpDown1.Value;
Thread[] tl = new Thread[n + 1];
threadList = tl.ToList();
for (int i = 0; i <= n; i++)
{
threadList[i] = new Thread(new ThreadStart(checkproxy));
}
for (int i = 0; i <= n; i++)
{
threadList[i].Start();
}
continueThreads = true;
proxyList = richTextBox1.Lines;
}
public void checkproxy()
{
while (continueThreads)
{
if (proxynum >= proxyList.Length)
{
continueThreads = false;
}
if (proxynum < proxyList.Length)
{
string proxy = proxyList[proxynum];
proxynum += 1;
string info = "";
try
{
Thread.Sleep(1000);
info += "Live || " + proxy + Environment.NewLine;
this.Invoke(new Action(() => richTextBox3.Text += info));
}
catch
{
}
}
}
}
}
}
this is screenshot error
Your method checkproxy uses Form1 class members (continueThreads, proxynum and others) directly.
If you really want do move it outside of this class (I'm not sure it is good idea since this method looks very closely related to your class) - you need to refactor this method and pass all class members it uses as method input parameters like
public void checkproxy(bool continueThreads.....)
Because this is a System.Windows.Forms.Form in original context.
To be able to Invoke interface update from another thread/async task, you need to use it (as you did correctly in your original code).
But once you move the function into separate class, there is no more notion of a Conntrol or Form there, so this is a class itself, which does not have Invoke implementation.
One possible solution: you need to refactor your method in a way, that he is able to call Form's function, that internally calls Invoke.
Related
Consider:
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//int[] val = { 0, 0};
int val;
if (textBox1.Text == "")
{
MessageBox.Show("Input any no");
}
else
{
val = Convert.ToInt32(textBox1.Text);
Thread ot1 = new Thread(new ParameterizedThreadStart(SumData));
ot1.Start(val);
}
}
private static void ReadData(object state)
{
System.Windows.Forms.Application.Run();
}
void setTextboxText(int result)
{
if (this.InvokeRequired)
{
this.Invoke(new IntDelegate(SetTextboxTextSafe), new object[] { result });
}
else
{
SetTextboxTextSafe(result);
}
}
void SetTextboxTextSafe(int result)
{
label1.Text = result.ToString();
}
private static void SumData(object state)
{
int result;
//int[] icount = (int[])state;
int icount = (int)state;
for (int i = icount; i > 0; i--)
{
result += i;
System.Threading.Thread.Sleep(1000);
}
setTextboxText(result);
}
delegate void IntDelegate(int result);
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
}
Why is this error occurring?
An object reference is required for the nonstatic field, method, or property 'WindowsApplication1.Form1.setTextboxText(int)
It looks like you are calling a non static member (a property or method, specifically setTextboxText) from a static method (specifically SumData). You will need to either:
Make the called member static also:
static void setTextboxText(int result)
{
// Write static logic for setTextboxText.
// This may require a static singleton instance of Form1.
}
Create an instance of Form1 within the calling method:
private static void SumData(object state)
{
int result = 0;
//int[] icount = (int[])state;
int icount = (int)state;
for (int i = icount; i > 0; i--)
{
result += i;
System.Threading.Thread.Sleep(1000);
}
Form1 frm1 = new Form1();
frm1.setTextboxText(result);
}
Passing in an instance of Form1 would be an option also.
Make the calling method a non-static instance method (of Form1):
private void SumData(object state)
{
int result = 0;
//int[] icount = (int[])state;
int icount = (int)state;
for (int i = icount; i > 0; i--)
{
result += i;
System.Threading.Thread.Sleep(1000);
}
setTextboxText(result);
}
More info about this error can be found on MSDN.
For this case, where you want to get a Control of a Form and are receiving this error, then I have a little bypass for you.
Go to your Program.cs and change
Application.Run(new Form1());
to
public static Form1 form1 = new Form1(); // Place this var out of the constructor
Application.Run(form1);
Now you can access a control with
Program.form1.<Your control>
Also: Don't forget to set your Control-Access-Level to Public.
And yes I know, this answer does not fit to the question caller, but it fits to googlers who have this specific issue with controls.
You start a thread which runs the static method SumData. However, SumData calls SetTextboxText which isn't static. Thus you need an instance of your form to call SetTextboxText.
Your method must be static
static void setTextboxText(int result)
{
if (this.InvokeRequired)
{
this.Invoke(new IntDelegate(SetTextboxTextSafe), new object[] { result });
}
else
{
SetTextboxTextSafe(result);
}
}
Credit to #COOLGAMETUBE for tipping me off to what ended up working for me. His idea was good but I had a problem when Application.SetCompatibleTextRenderingDefault was called after the form was already created. So with a little change, this is working for me:
static class Program
{
public static Form1 form1; // = new Form1(); // Place this var out of the constructor
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(form1 = new Form1());
}
}
I actually got this error because I was checking InnerHtml for some content that was generated dynamically - i.e. a control that is runat=server.
To solve this I had to remove the "static" keyword on my method, and it ran fine.
From my looking you give a null value to a textbox and return in a ToString() as it is a static method. You can replace it with Convert.ToString() that can enable null value.
Make the function static. This must solve your problem.
The essence, and solution, to your problem is this:
using System;
namespace myNameSpace
{
class Program
{
private void method()
{
Console.WriteLine("Hello World!");
}
static void Main(string[] args)
{
method();//<-- Compile Time error because an instantiation of the Program class doesnt exist
Program p = new Program();
p.method();//Now it works. (You could also make method() static to get it to work)
}
}
}
This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 6 years ago.
I have a form with a label, also an external class. In my class, I have a for loop of 1 to 1000. How can I show the value of 1 to 1000 from my class to my form label?
//external class
public class TestClass
{
public void myLoop()
{
for (int i = 1; i <= 1000; i++)
{
// show value of i to label
}
}
}
Assuming you have a reference to your form as form1, and that form has a label named label1 that is public/accessible to TestClass:
public class TestClass
{
public void myLoop()
{
for (int i = 1; i <= 1000; i++)
{
// show value of i to label
form1.label1.Text = i.ToString();
// allow message pumping to redraw the label
Application.DoEvents();
// pause long enough to see it before the next one happens
System.Threading.Thread.Sleep(100);
}
}
}
I wouldn't recommend using Application.DoEvents for production code normally; but if you are running the UI thread and not using async code, this would be the "hacky" way to get all the window events pumping (mostly WM_PAINT to get the label to redraw itself) during your loop.
A better way is to use events:
public class TestClass {
public class ProgressEventArgs : EventArgs {
public int Value { get; set; }
}
public event EventHandler<ProgressEventArgs> Progress;
public void myLoop() {
for (int i = 0; i <= 1000; ++i) {
var evt = Progress;
if (evt != null) {
evt.Invoke(this, new ProgressEventArgs() { Value = i; });
}
}
}
}
and handle that event in the form:
public class TestForm : Form {
private somevent_click(object sender, EventArgs evt) {
var test = new TestClass();
test.Progress += test_Progress;
test.myLoop();
}
private void test_Progress(object sender, TestClass.ProgressEventArgs evt) {
label1.Text = evt.Value;
}
}
Note that these will happen in the same thread, so depending on what else you do in your loop, you may not get message pumping. Consider using a background thread or async code instead.
So i have written this tool that receives strings through a named pipe from another process. I want to pass the string that i receive from my main method to one of my forms but whenever i try it with a string constructor it seems like the values are empty.
I have a feeling that i did something wrong with the constructor or that the string isn't received from my currently running form...
Here my method for catching and sending the string in the main class:
public static async void startServer()
{
Task.Factory.StartNew(() =>
{
using (NamedPipeServerStream pipeStream = new NamedPipeServerStream("PipeToProgram"))
{
pipeStream.WaitForConnection();
using (StreamReader sr = new StreamReader(pipeStream))
{
string message;
while ((message = sr.ReadLine()) != null)
{
Form1 form = new Form1(message); //passing the string
}
startServer(); //restarts server after passing string
}
}
});
}
Here my constructor in Form1:
public Form1(string str)
{
InitializeComponent();
MessageBox.Show(str); //message arrives
addToList(str);
}
Here my addToList method:
public void addToList(string str)
{
MessageBox.Show(str); //arrives
textBox1.Text = str; //not arriving/showing in form
}
My main method:
[STAThread]
static void Main(string[] args)
{
if (m.WaitOne(TimeSpan.Zero, true))
{
startServer();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
startClient("message");
}
}
Default constructor of Form1:
public Form1()
{
InitializeComponent();
comboBox1.SelectedIndex = 0;
comboBox2.SelectedIndex = 1;
Timer_start();
checkWindowTimer_start();
checkBox1.FlatAppearance.BorderSize = 0;
}
What am i doing wrong? Is it because of the re-initializing of the components? But when i don't provide the InitializeComponents the tool won't start anymore
This feels to be something very simple but im struggling with this for quite a while now and i would greatly appreciate help from you guys :)
Thanks in advance
Ravand
when editing the UI from a multithreaded application you will likely need to use Invoke. you can only edit the UI from the thread it was started on
take this example:
public partial class Form1 : Form
{
static Random rand = new Random();
public Form1()
{
InitializeComponent();
System.Threading.Tasks.Task.Factory.StartNew(changetextfromanotherthread);
}
void changetextfromanotherthread()
{
for (int x = 0; x < 100; x++)
{
Invoke((Action)(() => { textBox1.Text = "" + rand.Next(); }));
System.Threading.Thread.Sleep(250);
}
}
}
this will successfully change the textbox 100 times from another thread.
if we remove invoke we will get and invalid operation exception when x == 1`. which states you cannot change the UI from another thread.
But you don't get that error do you
second remove the call to Sleep(250). now the textbox gets changed once and no error. (I really have no idea why) which is similar to your problem.
anyways even if some of my points aren't valid for this context, change the textbox from inside Invoke.
I have been recently learning C# and have a problem I just cant seem to wrap my head around. Please forgive me if this is noobish as I am very new to C# but my question is about delegates and invoke.
I have read many many tutorials online and watched many video tutorials about this as well but I am still getting the same error in my code and I just dont seem to grasp the subtleties. As I understand it a delegate is a pointer to a function and can be used to invoke that function from say another thread to update a textbox. I understand creating a delegate, that much I think I am doing right but when I invoke the delegate from a threat I always get the error Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
The callback appears to be functional as it is calling the function that it is designed to however it does not seem to do it on the correct thread which I thought was the whole point of doing it this way. I know there is the option to set that warning break to false but I would rather learn what I am doing wrong and how to code this type of method properly. I appreciate any help, suggestions or answers you can provide as I am not sure any more of the tutorials are getting me any closer at this point to understanding where I have gone wrong.
My code is very basic and as I am just trying to understand the most basic concepts of properly coding for multithreading. Below is my code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Threading;
using System.Reflection;
namespace WindowsFormsApplication3
{
//declair delegate name(vars) CORRECT
public delegate void Textboxdelegate(Int64 MyVar);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
runme();
}
public void runme()
{
textBox1.Text = "87";
textupdate(44);
int target = 0;
Textboxdelegate TD = new Textboxdelegate(textupdate);
Number number = new Number(target, TD);
TD(11);
Thread thread1 = new Thread(new ThreadStart(number.worker));
thread1.Start();
}
public void textupdate(Int64 cntr)
{
textBox1.Text += cntr.ToString();
}
}
class Number
{
int _target;
Textboxdelegate _callbackMethod;
public Number(int target, Textboxdelegate TDD)
{
this._target = target;
this._callbackMethod = TDD;
}
public void worker()
{
Int64 counter = 0;
byte[] lifeforms = new byte[2146435071];
for (long y = 1; y <= 2146; y++)
{
for (long X = 1; X <= 1000000; X++)
{
lifeforms[X * y] = 20;
}
counter += 1;
if(_callbackMethod != null)
{
_callbackMethod(counter);
}
}
MessageBox.Show("Done!");
}
}
}
This crude example should do it for what you want to do:
//public delegate void Textboxdelegate(Int64 MyVar);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Action<Int64> Textboxdelegate;
public void runme()
{
textBox1.Text = "87";
textupdate(44);
int target = 0;
Textboxdelegate = textupdate;
Number number = new Number(target, Textboxdelegate,this);
Textboxdelegate(11);
Thread thread1 = new Thread(new ThreadStart(number.worker));
thread1.Start();
}
public void textupdate(Int64 cntr)
{
textBox1.Text += cntr.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
runme();
}
}
class Number
{
int _target;
Action<Int64> _callbackMethod;
Form1 frm;
public Number(int target, Action<Int64> act,Form1 frm)
{
this._target = target;
this._callbackMethod = act;
this.frm = frm;
}
public void worker()
{
Int64 counter = 0;
byte[] lifeforms = new byte[214643507];
for (long y = 1; y <= 2146; y++)
{
for (long X = 1; X <= 100000; X++)
{
lifeforms[X * y] = 20;
}
counter += 1;
if (_callbackMethod != null)
{
if (frm.InvokeRequired)
{
frm.Invoke(_callbackMethod,new object[]{counter});
}
else
{
_callbackMethod(counter);
}
}
}
MessageBox.Show("Done!");
}
}
Controls have thread-afinity,meaning they can only be accessed from the thread that created them,and you where accessing them by another thread.Now the Invoke method of the Control class(the base of form and all its controls)will allow you to safelly access them(very summarized explanation).
I am trying to follow this example from MSDN: http://msdn.microsoft.com/en-us/library/a1hetckb.aspx
I think i'm doing everything they did but i keep getting this error: Parameter count mismatch
Here is my code:
Form1:
namespace ETL
{
public partial class Form1 : Form
{
private Thread myThread;
public delegate void delegatePrintoutProcess(string myString);
public delegatePrintoutProcess myDelegate2;
...
private void startParseToolStripMenuItem_Click(object sender, EventArgs e)
{
myDelegate2 = new delegatePrintoutProcess(updatePrintoutMethod);
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
public void updatePrintoutMethod(string text)
{
// this.richTextBox1.Text = text;
}
private void ThreadFunction()
{
parseFile myThreadClassObject = new parseFile(this);
myThreadClassObject.getFilePath = filePath;
myThreadClassObject.Run();
}
}
parseFile class:
namespace ETL
{
public class parseFile
{
Form1 myFormControl1;
public parseFile(Form1 myForm)
{
//get a handle on the main form
myFormControl1 = myForm;
}
String myString;
public void Run()
{
for (int i = 1; i <= 5; i++)
{
myString = "Step number " + i.ToString() + " executed";
Thread.Sleep(400);
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle with
// the specified list of arguments.
myFormControl1.Invoke(myFormControl1.myDelegate,
new Object[] { myString }); //error here
}
}
}
I'm pretty sure i've followed the provided example, so not sure what is going on.
Thanks
jason
Guess (as no code to prove) - type of myDelegate is "function with 0 or 2 arguments", unlike myDelegate2 that you probably wanted to call.