循环中的触发事件不是按顺序更新UI

时间:2015-11-29 17:08:03

标签: c# multithreading events delegates

我试图在UI上更新长期运行操作的状态。我创建了一个基于演示表单的应用程序,任务它有多行,每行都有几天,每行datagrid中的默认值为0,一旦计算文件计算一天的迭代,它将更新UI并设置1那天。

我正在使用线程,委托和事件来实现它,如果我在两个事件调用之间放置Thread.Sleep(100),它正在按预期工作。如果我把" Thread.Sleep(100)"在最后一个嵌套for循环中然后它按预期更新UI但是一旦我删除它并在没有睡眠的情况下运行循环,那么它会跳过UI上的一些列并直接更新最后几个/随机列,如附图所示(没有线程休眠的我的代码的输出图像)只有最后一列正在更新。

如果我没有弄错,所有的事件都按顺序被解雇,那么他们也应该按顺序更新UI,但它没有发生,我不知道为什么。我不想做这个睡眠的事情,因为我在实际应用程序中有大约14个调用UI状态更新,它将在一个循环下运行所以如果它放入睡眠(100)那么它将花费我很多,是否有没有睡觉的任何方式吗?

Image of output of my code without thread sleep

public class Class1 : IGenerate
{
    public event MessageEventHandler OnMessageSending;
    public void LongOperationMethod(BindingList<Status> _statusData)
    {
        if (OnMessageSending != null)
        {
            MessageEventArgs me = new MessageEventArgs();

            /// Loop for 2-3 Weeks
            for (;  ; ){
                /// Loop for 7 day
                for (; ; )
                {
                    /// Calculation on everyday
                    for (int j = 0; j != 1000; ++j)
                    {
                        // to do
                    }

                    me.weekNo = k;
                    me.DayNo = i;
                    OnMessageSending(me);

                }
            }
            me.Message = "Process completed successfully...";
            OnMessageSending(me);
        }
        else
        {
            throw new ArgumentException("Event hasn`t been rised, so we cannot continue working.");
        }
    }
}


**UI file:**
<pre><code>


 public partial class Form1 : Form
        {
            BindingList<Status> _statusData = new BindingList<Status>();
            delegate void StringParameterDelegate(string value);
            Class1 cls = new Class1();
            public Form1()
            {
                InitializeComponent();
                labelProgress.Text = "";
            }

            private void button1_Click_1(object sender, EventArgs e)
            {
                for (int i = 1; i <= 2; ++i)
                {
                    _statusData.Add(new Status { Week = "Week" + i, Day1 = 0, Day2 = 0, Day3 = 0, Day4 = 0, Day5 = 0, Day6 = 0, Day7 = 0 });
                }

                dataGridView1.DataSource = _statusData;
             }

            private void button2_Click(object sender, EventArgs e)
            {
                Thread t1 = new Thread(() => StartingThread(_statusData));
                t1.Start();
            }

            void StartingThread(BindingList<Status> _statusData)
            {
                IGenerate generate = new Class1();
                generate.OnMessageSending += new MessageEventHandler(generate_OnMessageSending);
                generate.LongOperationMethod(_statusData);
            }

            private void generate_OnMessageSending(MessageEventArgs e)
            {
                int weekNo = e.weekNo;
                int dayNo = e.DayNo;
                this.dataGridView1.BeginInvoke(new MethodInvoker(() => dataGridView1.Rows[e.weekNo].Cells[e.DayNo + 1].Value = 1));
                this.labelProgress.BeginInvoke(new MethodInvoker(() => this.labelProgress.Text = e.Message));

            }
        }
</code></pre>

1 个答案:

答案 0 :(得分:1)

看起来你每次都发送function dataSort(columnNum) { var artDataTable = document.getElementById('table'); var dataArray = []; for (var I = 1; I < artDataTable.rows.length; i++) { var r = artDataTable.rows[i]; var rowData = r.cells[columnNum].innerText; dataArray.push([rowData, r]); } dataArray.sort(); for (var j = 0; j < dataArray.length; j++) { artDataTable.appendChild(dataArray[j][1]); } dataArray = null; } 的同一个实例,只是在后台线程上更新那个实例。这意味着UI线程上的事件处理程序将检索循环中正在更新的MessageEventArgs的完全相同的实例!当您的UI处理程序获得MessageEventArgs时,其MessageEventArgs.weekNo属性很可能已被循环的下一次迭代修改,因为它们在不同的线程上运行。

要解决此问题,请在每次致电.DayNo时创建MessageEventArgs的新实例。

相关摘要:

OnMessageSending()