如何将函数变量传递至线程?代码报错求助
问题解决:线程参数传递与UI线程访问问题
1. 线程传参报错的原因
你代码里的错误是因为ThreadStart委托要求绑定无参数方法,但你直接写Worker(labelnode, id)是在创建线程时就执行了该方法,而非将方法作为委托传递给线程,这不符合线程构造的要求。
2. 解决线程传参的两种方案
方案一:使用ParameterizedThreadStart
把需要传递的参数打包成对象(比如Tuple),修改Worker方法接收object类型参数后拆包使用:
private void button1_Click(object sender, EventArgs e) { treeView1.BeginUpdate(); TreeNode labelnode = treeView1.Nodes[0].Nodes.Add("Label" + labelnum.ToString()); treeView1.EndUpdate(); string id = "1"; // 打包参数为Tuple var threadParam = Tuple.Create(labelnode, id); Thread thread = new Thread(new ParameterizedThreadStart(Worker)); thread.Start(threadParam); } private void Worker(object paramObj) { var param = (Tuple<TreeNode, string>)paramObj; TreeNode labelnode = param.Item1; string id = param.Item2; while (true) { Thread.Sleep(50); // 跨线程访问UI控件必须切换到UI线程 bool isSelected = false; if (treeView1.InvokeRequired) { isSelected = (bool)treeView1.Invoke(new Func<bool>(() => labelnode.IsSelected)); } else { isSelected = labelnode.IsSelected; } if (isSelected) { // showProperties若操作UI,也要通过Invoke切换线程 if (treeView1.InvokeRequired) { treeView1.Invoke(new Action(() => showProperties("label", id))); } else { showProperties("label", id); } } } }
方案二:使用Lambda表达式捕获外部变量
用Lambda表达式直接包裹带参数的Worker调用,自动捕获外部的labelnode和id,代码更简洁:
private void button1_Click(object sender, EventArgs e) { treeView1.BeginUpdate(); TreeNode labelnode = treeView1.Nodes[0].Nodes.Add("Label" + labelnum.ToString()); treeView1.EndUpdate(); string id = "1"; // Lambda表达式捕获变量,直接传递带参方法 Thread thread = new Thread(() => Worker(labelnode, id)); thread.Start(); } private void Worker(TreeNode labelnode, string id) { while (true) { Thread.Sleep(50); // 跨线程访问UI控件必须切换到UI线程 bool isSelected = false; if (labelnode.TreeView.InvokeRequired) { isSelected = (bool)labelnode.TreeView.Invoke(new Func<bool>(() => labelnode.IsSelected)); } else { isSelected = labelnode.IsSelected; } if (isSelected) { // showProperties若操作UI,同样需要Invoke切换线程 if (labelnode.TreeView.InvokeRequired) { labelnode.TreeView.Invoke(new Action(() => showProperties("label", id))); } else { showProperties("label", id); } } } }
3. 关键注意点:跨线程访问UI控件
后台线程不能直接访问或操作UI控件的属性、方法,否则会触发跨线程操作异常。上述代码中通过InvokeRequired判断是否需要切换线程,再用Invoke将操作委托到UI线程执行,这是必须的步骤。
内容的提问来源于stack exchange,提问作者felix
相关产品推荐
相关产品推荐

