TreeView的两个WinForms之间的Invoke方法应该在哪里处理?

537*_*037 5 .net c# treeview invoke winforms

我有两个WinForms(SettingfrmMain).我在Setting的表单中有一个TreeView,我想以FillTree第二种形式调用它的方法frmMain.

我正在使用它TreeView.Invoke来进行线程化.

这是我在Setting的表单中填充TreeView的代码:

TreeNode parentNode;
public void FillTree(DataTable dtGroups, DataTable dtGroupsChilds)
{
    treeViewGroups.Nodes.Clear();
    if (dtGroups == null) return;
    foreach (DataRow rowGroup in dtGroups.Rows)
    {
        parentNode = new TreeNode
        {
            Text = rowGroup["Groupname"].ToString(),
            Tag = rowGroup["Groupid"]
        };
        treeViewGroups.Invoke(new Add(AddParent), new object[] { parentNode });

        if (dtGroupsChilds == null) continue;
        foreach (DataRow rowUser in dtGroupsChilds.Rows)
        {
            if (rowGroup["Groupid"] == rowUser["Groupid"])
            {
                TreeNode childNode = new TreeNode
                {
                    Text = rowUser["Username"].ToString(),
                    Tag = rowUser["Phone"]
                };
                treeViewGroups.Invoke(new Add(AddParent), new object[] { childNode });
                System.Threading.Thread.Sleep(1000);
            }
        }
    }
    treeViewGroups.Update();
}

public delegate void Add(TreeNode tn);

public void AddParent(TreeNode tn)
{
    treeViewGroups.Nodes.Add(tn);
}

public void AddChild(TreeNode tn)
{
    parentNode.Nodes.Add(tn);
}
Run Code Online (Sandbox Code Playgroud)

FillTree 从上面的代码的方法,我想在我的第二种形式frmMain中调用它,我尝试这样:

Settings settingsWindow;
public frmMain()
{
    InitializeComponent();

    settingsWindow = new Settings(this);
}

private void SomeMethod()
{
    //Two DataTables (dt1 and dt2) are passed from frmMain form

    settingWindow.FillTree(dt1, dt2);
}
Run Code Online (Sandbox Code Playgroud)

当我调用FillTree方法时它会向我显示如下错误:

在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke.

我真的想知道,在我的第二个winform中应该在哪里处理TreeView的Invoke方法frmMain


我正在关注这些链接(但没有用):

1)在背景线程上填充TreeView

2)如何从另一个线程在树视图中添加对象

3)如何调用backgroundworker dowork事件调用的方法?


编辑可视化问题

我用TreeView尝试了它不工作然后我用ListBox尝试但问题仍然相同.

问题:我在WinForm中有一个方法(填充我的ListBox)settingsWindow,我想在我的第二个WinForm中调用该方法frmMain.

Settings 表格截图:

在此输入图像描述

frmMain 表格截图:

在此输入图像描述

问题GIF:

在此输入图像描述

设置表单ListBox填充代码:

public void PopulateGroupListData(DataTable dt)
{
    listGroups.DataSource = null;

    listGroups.DisplayMember = "GroupName";
    listGroups.ValueMember = "Groupid";
    listGroups.DataSource = dt;

    if (listGroups.Items.Count > 0)
        listGroups.SelectedItem = listGroups.Items[0];
}
Run Code Online (Sandbox Code Playgroud)

调用PopulateGroupListData第二种形式frmMain的方法:

void onCompleteReadFromServerStream(IAsyncResult iar)
{
    /... some code

    String[] arr1 = ServerMessage[1].Split('&');
    string Groupid1 = arr1[0];
    string GroupName1 = arr1[1];
    GroupsList.Rows.Add(Groupid1, GroupName1);
    settingsWindow.PopulateGroupListData(GroupsList);

    /... some code
}
Run Code Online (Sandbox Code Playgroud)

jsa*_*ics 2

订阅HandleCreated事件并填充事件处理程序中的树。

在此输入图像描述

public partial class Form1 : Form
{
    Form2 settingsWindow;

    public Form1()
    {
        InitializeComponent();
    }

    private void SettingsWindow_HandleCreated(object sender, EventArgs e)
    {
        var dt1 = new SampleTable1();
        var dt2 = new SampleTable2();

        settingsWindow.FillTree(dt1, dt2);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        settingsWindow = new Form2();
        settingsWindow.HandleCreated += SettingsWindow_HandleCreated;
        settingsWindow.ShowDialog();
    }
}
Run Code Online (Sandbox Code Playgroud)

作为奖励,我们还修复了一些FillTree方法问题,以便可以正确构建树。

public void FillTree(DataTable dtGroups, DataTable dtGroupsChilds)
{
    treeViewGroups.Nodes.Clear();
    if (dtGroups == null) return;
    foreach (DataRow rowGroup in dtGroups.Rows)
    {
        parentNode = new TreeNode
        {
            Text = rowGroup["Groupname"].ToString(),
            Tag = rowGroup["Groupid"]
        };
        treeViewGroups.Invoke(new Add(AddParent), new object[] { parentNode });

        if (dtGroupsChilds == null) continue;
        foreach (DataRow rowUser in dtGroupsChilds.Rows)
        {
            if ((int)rowGroup["Groupid"] == (int)rowUser["Groupid"])
            {
                TreeNode childNode = new TreeNode
                {
                    Text = rowUser["Username"].ToString(),
                    Tag = rowUser["Phone"]
                };
                treeViewGroups.Invoke(new Add(AddChild), new object[] { childNode });
                //System.Threading.Thread.Sleep(1000);
            }
        }
    }
    treeViewGroups.Update();
}
Run Code Online (Sandbox Code Playgroud)

回答您的后续问题:如果Form2已经可见,则不会发生您报告的异常,因为此时窗口的句柄已创建,如下所示。

在此输入图像描述

public partial class Form1 : Form
{
    Form2 settingsWindow;
    SampleTable1 dt1;
    SampleTable2 dt2;
    int groupid = 1;
    int userid = 101;

    public Form1()
    {
        InitializeComponent();

        dt1 = new SampleTable1();
        dt2 = new SampleTable2();

        dt1.AddGroup(groupid);
        dt2.AddUser(groupid, userid++);
        dt2.AddUser(groupid, userid++);

        dt1.AddGroup(++groupid);
        dt2.AddUser(groupid, userid++);
        dt2.AddUser(groupid, userid++);
        dt2.AddUser(groupid, userid++);
    }

    private void SettingsWindow_HandleCreated(object sender, EventArgs e)
    {
        settingsWindow.FillTree(dt1, dt2);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        settingsWindow = new Form2(this);
        settingsWindow.HandleCreated += SettingsWindow_HandleCreated;
        settingsWindow.ShowDialog();
    }

    public void UpdateData(string groupname)
    {
        dt1.AddGroup(++groupid, groupname);
        dt2.AddUser(groupid, userid++);
        dt2.AddUser(groupid, userid++);

        settingsWindow.FillTree(dt1, dt2);
    }
}
Run Code Online (Sandbox Code Playgroud)

Form2保持与您已有的相同,只需为新按钮添加一个事件处理程序:

    private void button1_Click(object sender, EventArgs e)
    {
        form1.UpdateData(textBox1.Text);
    }
Run Code Online (Sandbox Code Playgroud)

回答您的第二个后续问题: UpdateData是为用户通过 提交新组的特定用例而创建的Form2。我宁愿为不同的用例提供特定的代码。请注意,必须咨询服务器是相当基本的UpdateData,或者更好的是,使用一些抽象接口,该接口可能在远程服务器中,也可能不在远程服务器中(好的设计要求它应该是不相关/透明的......),然后返回要在 Form2 中显示的字符串消息。但是,这样做不会增加对该示例的有限范围的目的的任何了解。它实际上会混淆您所报告的根本问题及其相应的解决方案。我们不要忘记,如果没有它,您最初问题中报告的异常就会立即返回给您......:O) 在此输入图像描述