我是C#语言的新手,我将非常感谢您对以下问题的任何帮助/反馈。
基本上,我试图开发一个程序,使它有两个类class1(主线程)和class2。 class1有一个按钮,class2启动一个线程并进行一些计算。如何从class2中的线程中的class2更新class1(main)中按钮的任何属性?
这是我想做的一个例子
// CLASS 1 is a win form
class1:form
{
public btn_click()
{
// call function startthread from class2
btn.Enabled = false;
startthread()
}
}
// CLASS 2 is not a winform
class2
{
public startthread()
{
Thread worker = new Thread(doCalculation)
}
public doCalculation()
{
// do some calculation then
// blahhh
// blahhh
// HERE I NEED SOMEHOW ENABLED MY BUTTON
}
}
答案 0 :(得分:2)
这取决于您正在使用的UI框架。例如,假设您要更新按钮上的文本。
如果您使用的是WPF,则可以使用:
class1Instance.TheButton.Dispatcher
.BeginInvoke( (Action) () => class1Instance.TheButton.Content = "Foo" );
使用Windows窗体,您可以使用:
class1Instance.TheButton
.BeginInvoke( (Action) () => class1Instance.TheButton.Text = "Foo" );
答案 1 :(得分:2)
您必须将修改代码带回主线程,无论其WPF或Winforms,对UI的跨线程访问是明确禁止(通常)还是强烈劝阻和错误。
有很多方法可以做到这一点,在Winforms中我通常使用Control.Invoke
,如下所示:
public void UpdateMyTextBox(string NewText)
{
if(InvokeRequired)
Invoke(new Action<string>(UpdateMyTextBox), NewText);
else
myTextBox.Text = NewText;
}
在此示例中,InvokeRequired
属性将检查是否在UI线程上调用它,如果没有,我们将调用Invoke
将请求放入UI线程。< / p>
在WPF中,您会注意使用Dispatcher
,并且以非常类似的方式执行此操作:
public void UpdateMyWpfTextBox(string NewText)
{
if(!CheckAccess())
Dispatcher.Invoke(new Action<string>(UpdateMyWpfTextBox), NewText);
else
myTextBox.Text = NewText;
}
答案 2 :(得分:0)
不确定你在这里尝试做什么,但考虑到问题,这是我能想出的最佳答案。我将假设这是一个winforms应用程序
Class2需要引用Class 1中的按钮。所以你需要将它传递给它。
Class2引用该按钮后,您可以尝试将该属性修改为
btn.Text = "New Text";
我将再次假设你已尝试过这条路线,遇到异常,所以你发布了你的问题。你得到异常的原因是你的btn和你的class2在不同的线程中运行。要解决这个问题,您可以在按钮上调用invoke。我经常这样处理。
private void SetButtonText(string newText) {
if (btn.InvokeRequired) {
Invoke((MethodInvoker)(() => SetButtonText(newText)));
}
else {
btn.Text = newText;
}
}