【问题标题】:Firing events in loop are not updating UI in sequence循环中的触发事件不会按顺序更新 UI
【发布时间】:2015-11-29 17:08:03
【问题描述】:

我正在尝试更新 UI 上的状态以进行长时间运行。我创建了一个基于演示表单的应用程序,任务它有多行,每一行都有天,数据网格的每一列中的默认值为 0,一旦计算文件计算了一天的一次迭代,它将更新 UI 并为此设置 1日。

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

如果我没记错的话,所有事件都是按顺序触发的,那么它们也应该按顺序更新 UI,但它没有发生,我不知道为什么。我不想做这个睡眠的事情,因为我在实际应用程序中有大约 14 次调用 UI 状态更新,它会在一个循环下运行,所以如果它放 sleep(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>

【问题讨论】:

    标签: c# multithreading events delegates


    【解决方案1】:

    看起来您每次都在发送相同的MessageEventArgs 实例,并且只是在后台线程上更新该实例。这意味着您在 UI 线程上的事件处理程序将检索到在循环中更新的完全相同的 MessageEventArgs 实例!当您的 UI 处理程序获得 MessageEventArgs 时,它的 .weekNo.DayNo 属性很可能已被循环的下一次迭代修改,因为它们在不同的线程上运行。

    要解决此问题,请在每次调用 OnMessageSending() 时创建一个新的 MessageEventArgs 实例。

    相关sn-p:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-23
      • 1970-01-01
      • 2015-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多