C# 线程控制。调用
我有一个函数C# 线程控制。调用,c#,multithreading,C#,Multithreading,我有一个函数 public void ShowAllFly() { cbFly.Items.Clear(); cbFly.Items.Add("Uçuş Seçiniz..."); dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); dsFly _mds = new dsFly();
public void ShowAllFly()
{
cbFly.Items.Clear();
cbFly.Items.Add("Uçuş Seçiniz...");
dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter();
dsFly _mds = new dsFly();
_mds.EnforceConstraints = false;
dsFly.tblFlyDataTable _m = _mds.tblFly;
_t.Fill(_m);
foreach (DataRow _row in _m.Rows)
{
cbFly.Items.Add(_row["FlyID"].ToString()+"-"+_row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString());
}
_Thread.Abort();
timer1.Enabled = false;
WaitPanel.Visible = false;
}
以这样的形式加载函数
{
_Thread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowAllFly));
_Thread.Start();
_Thread.Priority = System.Threading.ThreadPriority.Normal;
}
但当我运行它时
在ShowAllFly函数中
cbFly.Items.Clear(); ---- HERE Gives ERROR LIKE Control.Invoke must be used to interact with controls created on a separate thread.
问题是什么?在另一个(ui)线程中对控件的交互需要这样调用:
Windows窗体中的线程有两条黄金法则:
- 除了创建控件“句柄”的线程(通常只有一个UI线程)之外,不要从任何线程中接触任何控件属性或方法(明确列出为OK的线程除外)
- 不要长时间阻塞UI线程,否则会使应用程序无响应
Control.Invoke
/BeginInvoke
来“整理”对UI线程的调用。您可以使用invokererequired
属性来测试是否需要调用Invoke
,但现在我个人倾向于这样做——当您不需要调用时,调用不会有太大的惩罚
C#3中的Lambda表达式(或C#2中的匿名方法)也使这一点更加令人愉快
例如,您可以使用:
cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear()));
所有的括号都有点妨碍,所以如果您使用的是C#3,您可能需要添加这样的扩展方法:
然后你可以做:
cbFly.Invoke(() => cbFly.Items.Clear());
这要简单得多。通常,您可以使用MethodInvoker
捕获需要在委托中访问的任何变量
有关更多详细信息,请参阅或
其次,我看到您正在使用Thread.Abort
——实际上是在您自己的线程上,尽管后面还有其他调用。为什么?中止除您自己的线程以外的任何线程都是一种“仅限紧急情况”类型的调用(通常在卸载应用程序之后),我看不出有任何理由在以后还有工作要做时中止当前线程…我一直觉得在这个特定问题上有帮助
在您的示例中,您试图从未创建控件的线程修改各种控件。若要在示例中解决此问题,请改为这样做(假设ShowAllFly()方法是表单上的一个方法):
为了强调@Jon Skeet的观点,我已经注释掉了中止线程的调用。这根线将自动结束。没有理由以这种方式中止它。它必须被调用。。。但调用必须等待主线程,我的意思是,您不会以这种方式得到错误,但这不是并行工作,如果您想同时执行多个进程,只需创建多个线程
Thread thread = new Thread(new delegate_method(method));//you must create delegate before
thread.start ();
Thread thread2 = new Thread(new delegate_method(method2));//you must create delegate before
thread.start ();
同时处理两个进程
void method ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void method2 ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void finish_thread()
{
if(invoke.Required)
{
//Here you have to call delegate method here with UI
BeginInvoke(new delegate_method(finish_thread));
}
else
{
//Now you can control UI thread from here and also you finished background work
//Do something working with UI thread
textBox.Text = "";
}
}
这是线程中控件工作的最佳方式 首先,您必须从单线程单元线程使用
...
Thread th = new Thread(yourThreadStart);
th.SetApartmentState(ApartmentState.STA);
th.Start();
...
接下来在代码之间复制此方法
public static void SetControlThreadSafe(Control control, Action<object[]> action, object[] args)
{
if (control.InvokeRequired)
try { control.Invoke(new Action<Control, Action<object[]>, object[]>(SetControlThreadSafe), control, action, args); } catch { }
else action(args);
}
享受…好的解决方案;byt我建议使用框架中的
操作
,而不是滚动(和维护)自己的。是的。。这几乎是做这件事的标准方法。之所以需要这样做,是因为textBox1.Text只能在创建textbox的线程上更改-调用是用于返回该线程的过程。@Fredrik:没错,但这个例子更常见,很大程度上是因为它存在的时间更长。因为他是最好的,我给了他一票,在我之前没有人给过(暗示,暗示)。
void method ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void method2 ()
{
//do something here -- working background Remember can not control any UI control from here
finish_thread()
}
void finish_thread()
{
if(invoke.Required)
{
//Here you have to call delegate method here with UI
BeginInvoke(new delegate_method(finish_thread));
}
else
{
//Now you can control UI thread from here and also you finished background work
//Do something working with UI thread
textBox.Text = "";
}
}
...
Thread th = new Thread(yourThreadStart);
th.SetApartmentState(ApartmentState.STA);
th.Start();
...
public static void SetControlThreadSafe(Control control, Action<object[]> action, object[] args)
{
if (control.InvokeRequired)
try { control.Invoke(new Action<Control, Action<object[]>, object[]>(SetControlThreadSafe), control, action, args); } catch { }
else action(args);
}
...
SetControlThreadSafe(textbox1, (arg) =>
{
textbox1.Text = "I`m Working in a Thread";
}, null);
...