问题描述
我很新的线程,所以我的想法和问题,可能会有点傻了:)
I'm very new to threads, so my thoughts and questions might be a bit silly :)
我填写的WinForm
控制从另一个线程的数据,所以我必须调用的invoke()
时,我米试图访问控制。
I fill WinForm
control with data from another thread, so I have to call Invoke()
when I'm trying to access control.
如果我理解正确的话, treeView.BeginInvoke(/ *一些行动()* /)
使这个动作<>()
在主线程中运行。但我射后不理这个的BeginInvoke()
,所以我不知道什么时候工作实际完成的。甚至当工作线程关闭,并执行返回到主线程,我不能肯定所有的的BeginInvoke()
方法已经执行完毕。
If I understand correctly, treeView.BeginInvoke(/*some Action()*/)
makes this Action<>()
run in main thread. But I "fire and forget" this BeginInvoke()
, so I can't know when the work is actually done. And even when worker thread closes and execution returns to main thread, I can't be sure that all BeginInvoke()
methods have finished execution.
这就是为什么即使是回到主线程后,我无法与控制
来我解雇管理的BeginInvoke()
。
That's why even after returning to main thread I can't manage with Control
to which I fired BeginInvoke()
.
的实际问题是 TreeView.ExpandAll()
不起作用。
看看下面的code段。
Take a look at the code snippet below.
private void btnGetTree_Click(object sender, EventArgs e) {
var treeViewWriter = new Thread(() => UpdateTreeView(new AddXmlNodeArgs(di, null), treeDirectoryContents));
treeViewWriter.Start();
treeViewWriter.Join();
treeDirectoryContents.ExpandAll();
}
// method runs on a worker thread
public static void UpdateTreeView(AddXmlNodeArgs args, TreeView treeView) {
// I will miss details... Here is the code that I run for every new TreeNode:
treeView.UpdateTree((TreeView tree) => {
tree.Nodes[0].Nodes.Add(newTreeNode); // treeView.Nodes[0]...
});
}
// Extension method for TreeView
public static void UpdateTree(this TreeView tree, Action<TreeView> code) {
if (tree.InvokeRequired)
tree.BeginInvoke(code, tree);
else
code.Invoke(tree);
}
我火 tree.BeginInvoke()
,但我不叫 EndInvoke会()
的任何地方。所以我在想,当 btnGetTree_Click
执行达到 treeDirectoryContents.ExpandAll()
- 不是所有的调用()
方法已经完成了他们的工作。这就是为什么 .ExpandAll()无法正常工作
。
I fire tree.BeginInvoke()
but I don't call EndInvoke()
anywhere. So I guess when in btnGetTree_Click
execution reaches to treeDirectoryContents.ExpandAll()
- not all Invoke()
methods have finished their work. Thats why .ExpandAll() doesn't work
.
纠正我,如果我错了,请大家给的建议如何解决这个问题。
Correct me if I'm wrong, and please give an advice how to solve this problem.
推荐答案
这是绝对错误的:
treeViewWriter.Start();
treeViewWriter.Join();
切勿从主线程中调用的Thread.join!,因为加入
响应的应用程序和所有那些的BeginInvoke
/ 调用
从来没有得到完全执行,因为没有被处理的消息。
Never call Thread.Join from Main Thread! because that Join
freezes the application and all those BeginInvoke
/Invoke
never gets fully executed because the message is not handled.
这是怎么的BeginInvoke()
的实际工作:
- 在它发送一些WM_USER(或类似)的消息循环。
- 在主线程中弹出
Application.DoEvents该邮件()
(或类似它总是叫Application.Run()
) - 在主线程执行传递给
委托的BeginInvoke()
- 执行主线程信号端(由
的WaitHandle
在的IAsyncResult
) -
EndInvoke会()
等待这样的信号(或者,如果的IAsyncResult
从的BeginInvoke
不会存储,它得到垃圾收集)
- It sends some WM_USER (or the like) on message loop.
- Main thread pops this message in
Application.DoEvents()
(or the like which is always called inApplication.Run()
) - Main thread executes the delegate passed to
BeginInvoke()
- Main thread signals end of execution (by
WaitHandle
inIAsyncResult
) EndInvoke()
waits for such signal (or ifIAsyncResult
fromBeginInvoke
is never stored, it gets garbage-collected)
所以,再一次:你eiter写纯粹的事件驱动或做这样的事情:
So again: you eiter write it purely event-driven or do something like this:
private bool done = false;
void click(object, EventArgs) {
thread.Start();
while(!done) Application.DoEvents();
tree.ExpandAll();
}
ADDON:Eihter使用的invoke()
(同步)和 Application.DoEvents()上面的循环
或者使用的BeginInvoke(),并致电ExpandAll以同样的方式(通过的BeginInvoke()从线程)
ADDON:Eihter use Invoke()
(synchronized) and the above loop with Application.DoEvents()
or use BeginInvoke() and call your ExpandAll the same way (through BeginInvoke() from the thread)
ADDON2:
private bool done;
void click(object,EventArgs) {
done = false; // init state
new Thread(work).Start(); // start backgound work
while(!done) Application.DoEvents(); // wait until done
finish(); } // finish the job in main thread
void work() {
Thread.Sleep(100); // do your work
done = true; } // signal done
void finish() {
whatever(); } // called on main thread
void click2(object,EventArgs) {
new Thread(work2).Start(); } // just start the hread
void work2() {
Thread.Sleep(100); // do your work
BeginInvoke(new Action(finish)); } // execute finish() on main thread
这篇关于如何保证异步方法完成工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!