在窗体上显示Usercontrol



我正试图在表单中显示一个用户控件。用户控件是一个带有鸟的gif图像的图片框。

我正在尝试这样做:

//main form
class Form1
{
    //play button
    private void gameButton1_Click(object sender, EventArgs e)
    {
        startPanel.Visible = false;
        Game g = new Game(this.gamePanel1);
        g.Start();
    }
}
class Game
{
    //is set to true after starting game
    public Game(gamePanel Display)
    {
        this.Display = Display;
    }
    bool Running = false;
    public gamePanel Display;
    public void Start()
    {
        Thread create_BirdsThread = new Thread(new ThreadStart(create_Birds));
        create_BirdsThread.Start();
        Running = true;
    }
    private void create_Birds()
    {
        while (Running)
        {
            //Display is a variable from class 'GamePanel'
            Display.CreateBirds();
            Display.Refresh();
            //this is just to test that one bird works
            Running = false;
        }
    }
}

class gamePanel : UserControl
{
    public void CreateBirds()
    {
        yBird y = new yBird();
            y.BackColor = System.Drawing.Color.Transparent;
            y.Location = new System.Drawing.Point(32, 56);
            y.Size = new System.Drawing.Size(96, 65);
            y.TabIndex = 1;
            if (this.InvokeRequired)
            {
                this.BeginInvoke((MethodInvoker)delegate()
                {
                    this.Controls.Add(y);
                });
            }
            else
            {
                this.Controls.Add(y);
            }
            y.Visible = true;
            y.BringToFront();
    }
}

但它在我的屏幕上没有显示一只鸟。如何解决这个问题?

谢谢!

*编辑:

我添加了主表单中的代码和Game.Start()方法

当然,这个代码不能工作。为了使Control.Begin/Invoke()工作,.NET首先需要知道代码需要在哪个特定线程上运行。它可以从Handle属性中计算出。哪个告诉它哪个特定线程拥有该窗口,底层winapi调用是GetWindowThreadProcessId()。

但这是代码中的一个先有鸡后有蛋的问题。在您的代码调用Controls.Add()方法之前,不会创建本机窗口。哪个必须在程序的UI线程上运行,即拥有Form对象的线程。Windows不允许其他线程拥有子窗口。

所以它不知道该调用哪个线程。如果你强制创建句柄,那么你的程序就会因为所有权规则而以不同的方式消亡。

关注更大的问题:您正在创建一个线程来运行需要几纳秒的代码。这些财产分配非常便宜。真正的工作是创建窗口,这需要许多微秒。您希望(并且需要)在UI线程上运行的。因此,使用线程根本没有任何好处,UI线程也不会在设置属性上花费几纳秒。

因此,完全去掉螺纹,继续前进。如果你正在做其他缓慢的事情,比如加载图像,那么这个可以在工作线程上轻松完成。

我已经修复了它。

我刚换了这个

if (this.InvokeRequired)
            {
                this.BeginInvoke((MethodInvoker)delegate()
                {
                    this.Controls.Add(y);
                });
            }

到这个

if (this.InvokeRequired)
            {
                this.Invoke(new MethodInvoker(this.yellow));
            }

最新更新