我试图在一个类中创建一个方法,并尝试通过单击按钮从另一个类(窗体)调用

这是我的第一堂课:

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); } } } 

这是我的第二堂课:

 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; } 

程序运行正常,我在TextBox只输出20作为输出。 我想要的是每次循环运行时的输出。

1,2,3,.........20和停止。

这是表单的设计

可能就像一个柜台。 我也试过使用Timer但不能这样做。

编辑:

@Mong Zhu我已经交叉检查了代码,仍然得到了exception。

这里有完整的代码供您参考:

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); } } } 

和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; } } 

如果您要将某些对象的进度报告回表单,则可以使用IProgress界面。 这里和这里都有很好的解释,但要将它转换为您给定的代码,它看起来像这样:

 public partial class Form1 : Form { private async void button1_Click(object sender, EventArgs e) { Progress reporter = new Progress(number => { textBox1.Text = number.ToString(); }); await Task.Run(() => MyClass1.MyMethod(reporter)); } } public class Class1 { public static int MyMethod(IProgress reporter) { for (int i = 1; i <= 20; ++i) { reporter.Report(i); //Thread.Sleep(100); } return i; } } 

注意

  • Class1不需要任何Form1知识。
  • 由于Class1.MyMethod是静态的,因此不需要它的实例。 如果要在Class1中修改字段/属性,则需要一个实例。 如果这是正确的,那真的取决于你。
  • IProgress需要.NET Framework 4.5

问题是您只将最后一个值传递给GUI。 你可以做的是将你想要用于显示的文本框传递给你的计数方法MyMethod 。 在那里你可以分配值。 您需要做的最后一件事是告诉应用程序使用Application.DoEvents();更新它的事件Application.DoEvents();

所以你的方法看起来像这样:

 public static int MyMethod(TextBox t) { int i = 0; for (int j = 1; j <= 20; j++) { i = j; t.Text = j.ToString(); Application.DoEvents(); Thread.Sleep(200); } return i; } 

别忘了包括:

 using System.Threading.Tasks; using System.Windows.Forms; 

你在Class1.cs

Form1的调用如下所示:

 private void button1_Click(object sender, EventArgs e) { _enemy = new Class1(this); int y = Class1.MyMethod(textBox1); } 

免责声明:@Default指出应该避免使用Application.DoEvents() 。 因此,另一种方法可能是优选的方法是使用计时器。 它有一个Tick事件,可以像你的for循环一样工作。 这个是System.Windows.Forms.Timer 。 您可以在Form1类中使用它:

 public partial class Form1 : Form { Timer t = new Timer(); public Form1() { InitializeComponent(); t.Interval = 200; // set the interval t.Tick += T_Tick; // register to the event } int i = 0; // this is your counting variable private void T_Tick(object sender, EventArgs e) { if (i<=20) // this takes care of the end { this.textBox1.Text = i.ToString(); i++; // count up } else { t.Stop(); // stop the timer if finished i = 0; // for the next time if you want to restart the timer } } private void button1_Click(object sender, EventArgs e) { t.Start(); // now just start your timer } } 

编辑

好吧,让事情变得更复杂但彻底。 您询问:

即在其他地方调用方法并在其他地方打印。 在其他地方我指的是另一个class级

如果你想在其他地方打印它会在其他地方;)我的意思是图形用户界面的责任是显示东西。 所以它应该继续展示。 你的方法的责任是计算,所以它应该继续计算。 要在C#中结合这两个职责, 事件的概念是一个强大的概念。 它允许您发送事件和传输数据。

您需要的第一件事是在Class1发出计数信号的事件:它有2个部分。 一个委托,它定义在触发事件时将调用的方法的结构,以及可以在另一个类中注册的委托类型的事件。 在你的情况下Form1

 public class Class1 { public delegate void Counter(int c); // this delegate allows you to transmit an integer public event Counter CountEvent; public Class1() { } 

我从Class1删除了Form1 _form的实例。 因为你不需要它来执行任务。 这也使您的Class1独立于GUI的实现。 (如果您明天决定更改TextBox的名称或选择Label来显示计数器,则Class1中将不会进行任何更改,仅在Form1 !)现在您可以在Form1中注册/订阅该事件创建事件触发时将调用的事件处理程序:

Form1中

 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(); } } 

由于我们不希望GUI在计数时冻结,因此我们将使用System.Threading.Thread在后台计数并通过事件传输数据。 现在这会导致问题,因为textBox1是由主线程创建的,如果你试图通过另一个线程访问它,它将崩溃。 因此,您需要使用BeginInvoke方法来显示通过事件传输的计数变量。

唯一剩下的就是实现计数方法。 如您所见,我删除了static关键字。 因为这样就必须将事件声明为static ,这意味着它只存在一次。 如果您尝试从第二个类订阅此事件,这将导致困难。

不是我们把你的循环放在一个线程中让线程运行。 在每次迭代时,它将触发事件并传输您的计数数据:

 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(); } 

开始这个方法是最简单的部分。 只需指定间隔,开始和结束,并调用方法,就像调用普通方法一样:

 private void button1_Click(object sender, EventArgs e) { MyCounterClass.MyCountMethod(300, 0, 10); } 

Etvoilà,你有一个可以计算并指示计数进度的类。 它独立于图形用户界面。 它必须依赖于Form1 。 每个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); _enemy.LoopInteration += OnLoopInteration; _enemy.MyMethod(); _enemy.LoopInteration -= OnLoopInteration; } private void OnLoopInteration(object sender, LoopCounterArgs e) { textBox1.Text = Convert.ToString(e.Iteration); } } } 

第二种forms:

 namespace WindowsFormsApplication2 { public class Class1 { public event EventHandler LoopInteration; public Class1( Form1 form ) { _form1 = form; } public void MyMethod() { for (int j = 1; j <= 20; j++) { LoopInteration?.Invoke(this, new LoopCounterArgs(j)); //Thread.Sleep(100); } } } // DON'T initialize this with new Form1(); private Form1 _form1; } 

然后,处理自定义事件args的新类:

 namespace WindowsFormsApplication2 { public class LoopCounterArgs : EventArgs { public int Iteration { get; set; } public LoopCounterArgs(int iteration) { Iteration = iteration; } } } 

我没有测试过,所以可能包含一些错误,但应该在那里...

您可能想要重新考虑textBox1.Text语句,因为它可以快速工作,该值可能显示为20,而实际上它已经为您完成了所有迭代。