繁体   English   中英

将在另一个线程中创建的UserControl添加到窗体

[英]Add a UserControl that is created in another thread to a form

我有一个名为MainAppForm(Thread1)的窗体的应用程序。 我有这种形式的面板,它将托管UserControls。

当用户单击按钮时,我想创建另一个线程(Thread2),该线程将创建UserControl的实例并调用Thread1上的方法以将UserControl添加到第一段中提到的面板中。

这就是我从Thread2调用主Thread1的方式

public class SecondThread
{
    public void start()
    {
        ModuleWindow userControl = new ModuleWindow(new Module.ModuleLayer());

        Global.SetModuleWindowThreadSafe(userControl);
    }
}

我的方法会将传入的用户控件添加到面板中。

public static class Global
{
    private delegate void SetModuleWindowThreadSafeDelegate(UserControl userControl);
    public static void SetModuleWindowThreadSafe(UserControl userControl)
    {
        if (Global.mainAppForm.pnlMain.InvokeRequired)
        {
            Global.mainAppForm.pnlMain.Invoke(
                new SetModuleWindowThreadSafeDelegate(SetModuleWindowThreadSafe),
                userControl);
        }
        else
        {
            Global.mainAppForm.pnlMain.Controls.Add(userControl);
        }
    }
}

在SetModuleWindowThreadSafe()方法中进行调用后,它引发

跨线程操作无效:从创建该线程的线程以外的线程访问控件“ menuStrip1”。

注意:menuStrip1是UserControl上的控件。

如何将第二个线程中创建的UserControl添加到面板中?

更新:

感谢您的回答。 我确信他们在某些方面会有所帮助,但对我而言并非如此。 原因是我的MainAppForm(AKTAP项目)和生成的UserControl(KKM项目)正在不同的Projets甚至解决方案中创建。 KKM的项目输出是一个.dll,我正在使用反射在运行时加载这些dll文件。 因此MainAppForm不知道每个dll中正在生成哪种类型的用户控件和控件。

我要按以下顺序进行操作:

1- AKTAP项目具有一个接口,该接口由KKM项目中的类实现。
2- KKM项目正在构建中,并将dll文件放入指定的目录。
3- AKTAP通过过滤第1节中提到的接口开始运行并使用反射加载dll文件。
4- AKTAP在KKM hich中调用方法将生成并返回用户控件。
5-AKTAP将返回的用户控件添加到MainAppForm。 (这是我在上面得到异常的地方。)

如何将第二个线程中创建的UserControl添加到面板中?

你不知道 您可以在UI线程中而不是在某些后台线程中创建UserControl。

如果要进行一些昂贵的CPU绑定计算以找出用户控件将需要的数据,请使用另一个线程来计算该数据 ,然后让UI线程获取该数据并创建UI控件以显示该数据。

服务是正确的-您不正确。

但是,您可以! 意思是有可能的。

从线程传递数据很复杂,但是System.ComponentModel.BackgroundWorker (WinForms的一部分)极大地简化了线程操作,并使诸如此类的任务变得很有趣。

这是一种使用两(2)个Windows窗体的通用技术,一个窗体作为另一个窗体中的变量。 两者都在同一个名称空间中(相同的项目等)。

表格1:

public partial class Form1 : Form
{

    private Button btnGetInteger;
    private Button btnGetMenuStrip;
    private Button btnGetString;
    private Form2 _form2;
    private Form2.ReturnType _getType;
    private Object _form2Argument;

    public Form1()
    {
        InitializeComponent();
        btnGetInteger = new Button();
        btnGetInteger.Click += Form2_GetInteger;
        btnGetMenuStrip = new Button();
        btnGetMenuStrip.Click += Form2_GetInteger;
        btnGetString = new Button();
        btnGetString.Click += Form2_GetString;
        Shown += (s, e) => { Form2_CreateMenuStrip(s, EventArgs.Empty); };
    }

    public void Form2_ThreadChanged(object sender, ProgressChangedEventArgs e)
    {
        var returned = (Form2.ReturnType)e.ProgressPercentage;
        switch (returned)
        {
            case Form2.ReturnType.MenuStrip:
                var menuStrip = (MenuStrip)e.UserState;
                this.Controls.Add(menuStrip);
                break;
            case Form2.ReturnType.Integer:
                var numberBack = (int)e.UserState;
                Text = String.Format("Form1 : (int){0}", numberBack);
                break;
            case Form2.ReturnType.String:
                var stringBack = e.UserState.ToString();
                Text = String.Format("Form1 : (String){0}", stringBack);
                break;
        }
    }

    public void Form2_ThreadCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        _form2Argument = null;
        if (e.Error != null)
        {
            String title;
            if (_form2 != null)
            {
                title = String.Format("{0}: {1}", _form2.Text, e.Error.GetType());
            } else
            {
                title = String.Format("Form2: {0}", e.Error.GetType());
            }
            MessageBox.Show(e.Error.Message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        if (_form2 != null)
        {
            _form2.Close();
            _form2.Dispose();
            _form2 = null;
        }
        btnGetInteger.Enabled = true;
        btnGetMenuStrip.Enabled = true;
        btnGetString.Enabled = true;
    }

    private void Form2_CreateMenuStrip(object sender, EventArgs e)
    {
        if (_form2 == null)
        {
            _getType = Form2.ReturnType.MenuStrip;
            var item = new ToolStripMenuItem(Text);
            item.Click += Form2_GetInteger;
            _form2Argument = item;
            Form2_StartWork();
        }
    }

    private void Form2_GetInteger(object sender, EventArgs e)
    {
        if (_form2 == null)
        {
            _getType = Form2.ReturnType.Integer;
            Form2_StartWork();
        }
    }

    private void Form2_GetString(object sender, EventArgs e)
    {
        if (_form2 == null)
        {
            _getType = Form2.ReturnType.String;
            Form2_StartWork();
        }
    }

    private void Form2_StartWork()
    {
        btnGetInteger.Enabled = false;
        btnGetMenuStrip.Enabled = false;
        btnGetString.Enabled = false;
        _form2 = new Form2();
        _form2.Show(); // Show returns immediately
        _form2.StartThread(this, _form2Argument, _getType);

    }

}

Form2_ThreadChangedForm2_ThreadCompleted都设置为PUBLIC,以便它们可以被Form2实例看到。

表格2:

public partial class Form2 : Form
{
    private ReturnType _getType; // thread safe
    private BackgroundWorker _bwThread;

    public enum ReturnType { MenuStrip, String, Integer }

    public Form2() // Do Not Call this method
    {
        InitializeComponent();
    }

    public void StartThread(Form1 parent, Object argument, ReturnType getType)
    {
        _getType = getType;
        if (_bwThread == null)
        {
            _bwThread = new BackgroundWorker() {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _bwThread.DoWork += ThreadWork;
            _bwThread.ProgressChanged += parent.Form2_ThreadChanged;
            _bwThread.RunWorkerCompleted += parent.Form2_ThreadCompleted;
        }
        if (!_bwThread.IsBusy)
        {
            _bwThread.RunWorkerAsync(argument);
        }
    }

    private void ThreadWork(object sender, DoWorkEventArgs e)
    {
        switch (_getType)
        {
            case ReturnType.MenuStrip:
                var menuStrip = new MenuStrip();
                if (e.Argument != null)
                {
                    var mi = (ToolStripMenuItem)e.Argument;
                    menuStrip.Items.Add(mi);
                }
                _bwThread.ReportProgress((int)_getType, menuStrip);
                break;
            case ReturnType.Integer:
                var numberBack = 1;
                _bwThread.ReportProgress((int)_getType, numberBack);
                break;
            case ReturnType.String:
                var stringBack = "Worker String";
                _bwThread.ReportProgress((int)_getType, stringBack);
                break;
        }
    }

}

如果您创建一个新的小型项目,其中有2个空窗体,分别称为Form1和Form2,则可以进入代码,然后简单地将上面的所有内容粘贴到这两个窗体中。

完成此操作后,只需在所有方法(公共方法和私有方法)上设置断点,以查看其工作方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM