C#Invoke()委托,字符串数组作为参数(winforms)

时间:2013-05-23 23:11:25

标签: c# arrays winforms delegates

我试图从一个单独的线程使用this.Invoke()来访问我的表单上的控件。我正在调用一个委托,该委托指向一个以字符串[]作为参数的方法。

关于我的代表声明的几行:

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;
}

这通常与我的其他代理一起使用各种参数(字符串,控制,表单和无参数),但每当我调用此Invoke()行时,我都会收到错误:“参数计数不匹配。”

我认为发生的事情是我的字符串数组被装入一个对象数组,并且委托试图将这些字符串作为单独的参数传递给该方法。因此,如果字符串数组中有“Bob”“Sally”和“Joe”,则它会尝试将LoadUsers调用为

LoadUsers("Bob", "Sally", "Joe");

显然与签名不符。

这听起来像是可能发生的事吗?我怎么能解决这个问题?

2 个答案:

答案 0 :(得分:5)

假设sUsernamesstring[],那么是,您需要使用

进行调用
Invoke(_dLoadUserSelect, new object[] { sUsernames });

.Net数组是协变的,所以这个赋值是有效的:

string[] sUsernames = new[] { "a", "b", "c" };
object[] objs = sUsernames;

当使用params参数调用方法时,数组直接传递,而不是作为参数数组中的第一个元素传递。您需要手动为Invoke创建参数数组,以获得您期望的行为。

答案 1 :(得分:0)

以下更改将解决问题(方法需要驻留在Form类中):

internal void LoadUsers(params string[] users)
{
    System.Action act = () =>
    {
        //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;
    });
    this.Invoke(act);
}

如果从表单外部调用,则方法LoadUsers至少应为internal,而不是private

由于我已将其封装在动作act中,因此现在可以通过this.Invoke(act);调用它。 现在,您可以在长时间运行的线程或任务上下文中安全调用LoadUsers,例如

private void ShowUsers_Click(object sender, EventArgs e)
{
    Task.Run(() =>
    { // long running task (e.g. database query running 20 seconds)
      Thread.Sleep(20000); // wait 20 seconds
      // populate the user's list
      string[] sUsernames = new[] { "Bob", "Sally", "Joe" };
      LoadUsers(sUsernames);
      // or, passed as params: LoadUsers("Bob", "Sally", "Joe");
    });
}

在此示例中,作为任务立即在click事件中运行操作可防止表单冻结并显示“未响应...”,因为事件只是对任务的处理,并在任务继续单独运行时立即退出


NB:

  • 动作act在这里从技术上讲是作为委托使用的,但是使用Lamba语法,声明(和理解)要容易得多。而且它节省了一些实现工作,因为您不需要先声明一个委托类型然后再使用它。
  • 使用params是可选的,但是如果您直接传递参数,它将简化调用LoadUsers的过程。您仍然可以根据需要传递数组。
  • 如果只需要更新一个控件(例如仅说lstUsers),则可以像lstUsers.Invoke(act);一样在控件上调用它。在这里这是不可能的,但值得一提。