我已经使用visual studio开始了一个典型的Windows窗体项目(c#)。我正在使用BackgroundWorker来填充TreeView控件并显示用户的当前进度。我必须使用Control.Invoke方法来访问我的TreeView控件的方法(如TreeView.Nodes.Add(string ...))。我有两个问题。
是否可以“自动”获取对调用委托方法的对象的引用?例如,当我调用myTree.Invoke(tbu,new object [] {myTree})时,我发送一个myTree对象作为该方法的参数。它是唯一可能的方式,还是我可以像EventHandlers那样做(比如“对象发送者”参数)?
最佳实践是什么:将用于委托的类方法声明为静态(本代码中的TreeBU),或者如下所示 - 为MainForm对象声明一个静态公共变量,然后在初始化委托时使用它object(TreeStart tbu = Program.thisForm.TreeBU)?
对不起我的c#和英文,并提前致谢!
namespace SmartSorting
{
public delegate void TreeStart(TreeView xmasTree);
static class Program
{
public static MainForm thisForm;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
thisForm = new MainForm();
Application.Run(thisForm);
}
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
backgroundWorker1.RunWorkerAsync(treeView1);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker1 = (BackgroundWorker) sender;
e.Result = stage1(worker1, (TreeView)e.Argument);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null) MessageBox.Show(e.Error.Message);
}
private bool stage1(BackgroundWorker wrkr, TreeView myTree)
{
TreeStart tbu = Program.thisForm.TreeBU;
myTree.Invoke(tbu, new object[] {myTree});
return true;
}
public void TreeBU (TreeView xmasTree)
{
xmasTree.BeginUpdate();
}
}
}
答案 0 :(得分:0)
您通常通过直接传递一个函数(必须与代理签名匹配)来分配一个委托!:
MyCrossThreadDelegateInstance += invokeMe;
或
new MyCrossThreadDelegate(invokeMe);
检查一下: 您在不同的线程上,并希望使用您的invokeMe()方法更新TreeControl。
private void invokeMe()
{
MyTree.BeginUpdate();
}
由于MyTree.BeginUpdate()的调用来自不同的线程,因此抛出了crossthread异常。 为了防止这种情况,我们修改了invokeMe()方法以避免抛出异常:
private void invokeMe()
{
if (MyTree.InvokeRequired)
MyTree.Invoke(new CrossThreadDelegate(invokeMe);
else
MyTree.BeginUpDate();
}
在调用u之前检查是否需要调用 - 当你尝试从不同的线程访问控件时,就是创建控件的控件。这样它就会尝试通过冒泡你的线程树来找到拥有并创建控件的线程。 如果Control.InvokeRequired返回true,则从下一个线程再次调用相同的方法(由委托传递)。重复此过程,直到找到拥有的线程。现在Control.InvokeRequired返回false,你的ELSE块在正确的线程上执行,而不会抛出一个crossthread异常。 有关详细信息,请参阅MSDN Control.Invoke
除非您希望您的委托在全局范围内可用,否则无需声明任何静态内容。
编辑:如果您按照原样使用BackgroundWorker,则ProgressChanged事件将完成工作,因为此事件在适当的线程(UI线程)上升。通过调用BackgroundWorker.ReportProgress()成员触发此事件。有关详细信息,请参阅MSDN - BackgroundWorker class