This is my first class:
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
/*_enemy = new Class1(this);
int y = Class1.MyMethod(0);
textBox1.Text = Convert.ToString (y);*/
}
private Class1 _enemy;
private void button1_Click(object sender, EventArgs e)
{
_enemy = new Class1(this);
int y = Class1.MyMethod();
textBox1.Text = Convert.ToString(y);
}
}
}
and this is my second class:
namespace WindowsFormsApplication2
{
public class Class1
{
public Class1( Form1 form )
{
_form1 = form;
}
public static int MyMethod()
{
int i = 0;
for (int j = 1; j <= 20; j++)
{
i = j;
//Thread.Sleep(100);
}
return i;
}
}
// DON'T initialize this with new Form1();
private Form1 _form1;
}
The program is running correctly and I am getting only 20 as output in the TextBox
. What I want is the output each time the loop runs.
Like 1,2,3,.........20
and stop.
Like a counter maybe. I also tried using Timer
but couldn't do that.
EDIT:
@Mong Zhu I have cross checked the code, still getting the exception.
For your reference here are the complete codes:
Form1.cpp
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
Class1 MyCounterClass;
private void Form1_Load(object sender, EventArgs e)
{
MyCounterClass = new Class1();
// register the event. The method on the right hand side
// will be called when the event is fired
MyCounterClass.CountEvent += MyCounterClass_CountEvent;
}
private void MyCounterClass_CountEvent(int c)
{
if (textBox1.InvokeRequired)
{
textBox1.BeginInvoke(new Action(() => textBox1.Text = c.ToString()));
}
else
{
textBox1.Text = c.ToString();
}
}
public Form1()
{
InitializeComponent();
}
private Class1 _enemy;
private void button1_Click(object sender, EventArgs e)
{
MyCounterClass.MyCountMethod(300, 0, 10);
}
}
}
and class1.cpp
namespace WindowsFormsApplication2
{
public class Class1
{
public delegate void Counter(int c); // this delegate allows you to transmit an integer
public event Counter CountEvent;
public Class1()
{
}
public void MyCountMethod(int interval_msec, int start, int end)
{
System.Threading.Thread t = new System.Threading.Thread(() =>
{
for (int i = start; i <= end; i++)
{
// Check whether some other class has registered to the event
if (CountEvent != null)
{
// fire the event to transmit the counting data
CountEvent(i);
System.Threading.Thread.Sleep(interval_msec);
}
}
});
// start the thread
t.Start();
}
// DON'T initialize this with new Form1();
private Form1 _form1;
}
}
If you are looking to report progress from some object back to your form you can use the
IProgress<T>
interface instead. It is well explained here and here but to translate it to your given code it would look something like this:Note that
Class1
does not need any knowledge ofForm1
.Class1.MyMethod
is static you do not require an instance of it. If you want to modify fields/properties in Class1 you need an instance. It's really up to you if this is correct or not.IProgress<T>
requires .NET Framework 4.5Maybe think about an event?
second form:
then, new class to handle the custom event args:
I haven't tested this so may contain some bugs, but should be pretty much there...
You might want to re-think the textBox1.Text statement as it'll work that quickly, the value may appear as 20, when in fact it has done all the iterations for you.
The problem is that you only pass the last value to the GUI. What you could do is to pass the textbox which you want to use for display into your counting method
MyMethod
. There you could assign the value. One last thing that you need to do is to tell the application to update it's events withApplication.DoEvents();
So your method would look like this:
don't forget to include:
in you Class1.cs
The call in
Form1
would look like this:Disclaimer: Application.DoEvents() should be avoided as pointed out by @Default. Therefore another approach and probably a preferable one would be to use a timer. It has a
Tick
event which could work like your for-loop. This one isSystem.Windows.Forms.Timer
. You can use it in theForm1
class:EDIT
Ok lets make things a little more complicated but thorough. You asked:
If you want to print it somewhere else it will be somewhere else ;) What I mean is that the responsibility of the graphical user interface is to display things. So it should remain displaying things. The responsibility of your method is to count up, so it should remain counting things up. To combine these two responsibilities in C# the concept of events is a powerfull one. It allows you to signal events and transmit data.
The first thing you need is an event to signal the counting in
Class1
: It has 2 Parts. A delegate which defines the structure of the method that will be called when the event is fired, and the event of the type of the delegate that can be registered in another class. In your case theForm1
.I removed the instance of
Form1 _form
fromClass1
. Because you don't need it for the task. Also this makes yourClass1
independent of the implementation of the GUI. (If you decide tomorrow to change the name of theTextBox
or choose aLabel
to display the counter, there will be no changes to make in theClass1
, only inForm1
!) Now you can register/subscribe to the event in theForm1
and create the eventhandler which will be called when the event is fired:Form1
Since we don't want the GUI to freeze when it is counting we will use a System.Threading.Thread to count in the background and transmit the data via the event. Now this will lead to problems, because the
textBox1
is created by the main thread and if you try to access it through another one it will crash. So you need to use the BeginInvoke method to display the counting variable which is transmitted via the event.The only thing that is left is to implement the counting method. As you see I removed the
static
keyword. Because that would make it necessary to declare the event also asstatic
and that would mean that it exist only one time. This will lead to difficulties if you would try to subscribe to this event from a second class.Not we take your loop and put it in a Thread and let the thread run. At each iteration it will fire the event and transmit your counting data:
To start the method is the easiest part. Just specify the interval, start and end and call the method as you would call a normal method:
Et voilà, you have a class which can count up and signal the counting progress. And it is independent of the graphical user interface. It has to dependencies on
Form1
. And every class remains taking care of their own responsibilities. Hope it helps