这是我的第一堂课:
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我已经交叉检查了代码,仍然得到了异常。
以下是完整的代码供您参考:
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;
}
}
答案 0 :(得分:3)
如果您要将某些对象的进度报告回表单,可以使用IProgress<T>
界面。很好地解释了here和here,但要将其翻译为您给定的代码,它看起来像这样:
public partial class Form1 : Form
{
private async void button1_Click(object sender, EventArgs e)
{
Progress<int> reporter = new Progress<int>(number =>
{
textBox1.Text = number.ToString();
});
await Task.Run(() => MyClass1.MyMethod(reporter));
}
}
public class Class1
{
public static int MyMethod(IProgress<int> reporter)
{
for (int i = 1; i <= 20; ++i)
{
reporter.Report(i);
//Thread.Sleep(100);
}
return i;
}
}
请注意
Class1
不需要了解Form1
。Class1.MyMethod
是静态的,因此您不需要它的实例。如果要修改Class1中的字段/属性,则需要一个实例。如果这是正确的话,这取决于你。IProgress<T>
需要.NET Framework 4.5 答案 1 :(得分:2)
问题是您只将最后一个值传递给GUI。您可以做的是将要用于显示的文本框传递给计数方法MyMethod
。在那里你可以分配值。您需要做的最后一件事是告诉应用程序使用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);
}
免责声明:{@ 3}}正如@Default所指出的那样。
因此,另一种方法可能是优选的方法是使用计时器。它有一个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
}
}
修改强>
好吧,让事情变得更复杂但彻底。你问:
即。在其他地方调用方法并在其他地方打印。在其他地方我指的是另一个班级
如果你想在其他地方打印它会在其他地方;)我的意思是图形用户界面的责任是显示东西。所以它应该继续显示。你的方法的责任是计算,所以它应该继续计算。要在C#中结合这两个职责,Application.DoEvents() should be avoided的概念是一个强大的概念。它允许您发送事件信号并传输数据。
您需要的第一件事是发出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()
{
}
我从Form1 _form
删除了Class1
的实例。因为你不需要它来执行任务。这也使您的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在计数时冻结,我们将使用events在后台计数并通过事件传输数据。现在这会导致问题,因为textBox1
是由主线程创建的,如果你试图通过另一个线程访问它,它将崩溃。因此,您需要使用System.Threading.Thread方法来显示通过事件传输的计数变量。
唯一剩下的就是实现计数方法。如您所见,我删除了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
。每个班级都在照顾自己的责任。
希望它有所帮助
答案 2 :(得分:1)
也许想想一个事件?
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);
}
}
}
第二种形式:
namespace WindowsFormsApplication2
{
public class Class1
{
public event EventHandler<LoopCounterArgs> 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,而实际上它已经为您完成了所有迭代。