我正试图从单独的线程使用this.Invoke()来访问窗体上的控件。我正在调用一个委托,该委托指向一个以字符串[]作为参数的方法。
关于我的delegate声明的几行:
public delegate void delVoidStringArray(string[] s);
public delVoidStringArray _dLoadUserSelect = null;
_dLoadUserSelect = LoadUsers;
字符串
从单独的线程调用委托:
Invoke(_dLoadUserSelect, sUsernames);
型
以及为处理窗体上的控件而调用的方法
private void LoadUsers(string[] users)
{
//Load the list of users into a ListBox
lstUsers.Items.AddRange(users);
//Load the state of a CheckBox on the form
chkUserAlways.Checked = Properties.Settings.Default.PreferDefaultUser;
}
型
这通常适用于我的其他具有各种参数(string,Control,Form和无参数)的委托,但每当我调用Invoke()行时,我都会得到一个错误:“参数计数不匹配。”
我认为发生的事情是,我的字符串数组被装箱到一个对象数组中,委托试图将这些字符串作为单独的参数传递给方法。因此,如果字符串数组有“Bob”、“Sally”和“Joe”,则它将尝试调用LoadUsers作为
LoadUsers("Bob", "Sally", "Joe");
型
显然和签名不符
这听起来像是可能发生的事情吗?我该如何解决这个问题?
2条答案
按热度按时间8wigbo561#
假设
sUsernames
是一个string[]
,那么是的,您需要使用字符串
.Net数组是协变的,所以这个赋值是有效的:
型
当使用params参数调用方法时,数组直接传递,而不是作为参数数组中的第一个元素传递。您需要手动创建
Invoke
的参数数组以获得预期的行为。bwntbbo32#
下面的更改将实现这一点(该方法需要驻留在
Form
类中):字符串
如果从窗体外部调用,则方法
LoadUsers
至少需要为internal
,而不是private
。因为我已经将它封装在Action
act
中,所以现在可以通过this.Invoke(act);
调用它。现在,您可以在长时间运行的线程或任务上下文中安全地调用LoadUsers
,如型
在此示例中,立即将click事件中的操作作为Task运行可防止窗体冻结并显示“Not responses...”,因为该事件只是踢出任务并立即退出,而任务则继续单独运行。
注:
act
在技术上被用作委托,但使用Lamba语法,声明(和理解)要容易得多。而且它节省了一些实现工作,因为您不需要先声明委托类型,然后再使用它。params
是可选的,但如果直接传递参数,则可以简化对LoadUsers
的调用。如果你愿意,你仍然可以传递一个数组。lstUsers
,你也可以在像lstUsers.Invoke(act);
这样的控件上调用它。在这里这是不可能的,但值得一提。