以并行或并发方式向面板添加控件

本文关键字:添加 控件 方式 并行 并发 | 更新日期: 2023-09-27 18:17:22

有一个面板,我想添加k控件到它。我想为每个控件指定任务,以便以后使用。所以:

*用一些其他代码更新下面的代码;请注意第三个代码*

*****Update*****
    Child Control : PacketData (can be a Button)
    Main Control : panel
    PlaceData() changes the left and top randomly.

我必须这样做:

        Parallel.For(0, k, (m) =>
        {
            tasks[m] = Task.Factory.StartNew(() =>
            {
                PacketData data = new PacketData();
                data.StartTime = sw.ElapsedMilliseconds;
                lock (data_adding_lock)
                {
                    IAsyncResult iar = panel1.BeginInvoke(new MethodInvoker(()=>{
                        PlaceData(ref data);
                        panel1.Controls.Add(data);
                    }));
                    panel1.EndInvoke(iar);
                    while (iar.IsCompleted ==false ) ;
                }

            });
        });

它有时很好,但有时不是,例如有时它只添加一个PacketData到面板控制。我是否丢失了一个竞争条件?

我也试过这个,但不工作…

        Parallel.For(0, k, (m) =>
        {
            tasks[m] = Task.Factory.StartNew(() =>
            {
                PacketData data;
                lock (data_instancing_lock) {
                 data = new PacketData();}
                data.StartTime = sw.ElapsedMilliseconds;
                    IAsyncResult iar = panel1.BeginInvoke(new MethodInvoker(()=>{
                        PlaceData(ref data);
                        lock(data_adder_lock){
                        panel1.Controls.Add(data);}
                    }));
                    panel1.EndInvoke(iar);

                //PlaceData(ref data);
            });
        });

*更新* *

这里是另一个例子(它不工作…)

object l1 = new object();
object l2 = new object();
private delegate void AdderDel(Button bb);
public Form1()
{
    InitializeComponent();
}
private void AddControl(Button x)
{
    lock (l2)
    {
        this.Controls.Add(x);
    }
}
private void Place(ref Button btn)
{
    Random rnd = new Random();
    int x = rnd.Next(0, this.Width-100);
    int y = rnd.Next(0, this.Height-100);
    btn.Left = x;
    btn.Top = y;
}
private void button1_Click(object sender, EventArgs e)
{
    int n = 5;
    Task[] t = new Task[n];
    AdderDel ad = new AdderDel(AddControl);
    Parallel.For(0, n, (k) =>
        {
            t[k] = Task.Factory.StartNew(() =>
            {
                Button b = new Button();
                b.Text = k.ToString();
                b.Height = 50;
                Place(ref b);

                this.BeginInvoke(ad, b);

            });
        });
}

为什么?

以并行或并发方式向面板添加控件

你的代码太复杂了,特别是因为我没有看到在这里使用并行的任何优势。(虽然在实际代码中可能有一些原因,但很难从示例中看出。)我认为你不应该使用并行,直到你知道它是如何工作的。应该避免使用试错法编程,因为这意味着你并不真正理解你自己的代码,所以它会导致bug。

但是代码中的实际问题与并行性无关。这是你不正确地使用Random。如果使用默认构造函数,Random将以当前时间作为种子。这意味着,如果您像这样在短时间内连续创建多个Random实例,它们都将返回相同的数字序列。这意味着所有的按钮都放置在表单上,除了它们都在同一个位置,所以您只能看到其中一个。

解决这个问题的最简单的方法是在一个字段中只有一个Random实例,并且只能从UI线程访问它,或者在使用它时使用锁。

如果你的代码可以工作,你可以考虑把它发布到代码审查堆栈交换,让它得到审查,并解释你实际上试图做什么。