Why does a delegate from a separate flow add incorrect data to UI flow?



  • Individual flows are computed, the result of which is to be taken into shape. For UI data transmission https://ru.stackoverflow.com/questions/418461/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%B0%D0%BC%D0%B8-%D0%B8%D0%B7-%D1%84%D0%BE%D0%BD%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0 Call Control.BeginInvoke

    using System.Windows.Forms;
    using System.Threading.Tasks;
    

    void addText(Form f, int res) {
    f.Controls.Add(new TextBox() { Text = res.ToString(), Dock = DockStyle.Top });
    }

    var f = new Form();
    f.Load += (s, e) => {
    Task.Run(() => {
    for(var result=0; result < 5; result++)
    f.BeginInvoke(new Action(() => addText(f, result) ));
    });
    };

    f.ShowDialog();

    But in shape, it's not right. In all the textBox's, it's five.


    Calling BeginInvoke from UI-pot.

    f.Load += (s, e) => {
    var result = "a";
    f.BeginInvoke(new Action(() => addText(f, result) ));
    result = "b";
    f.BeginInvoke(new Action(() => addText(f, result) ));

    ?

    But in shape, there are also incorrect values. The textBox is "b."
    Why do you get the right result in shape?
    Is it possible to get rid of BeginInvoke's calls in different parts of the code?



  • BeginInvoke &apos; s call puts the delegate in a special turn that is being processed in the UI-stream. At the time of the delegate &apos; s call, there is a new meaning in the result, not that at the time of the BeginInvoke challenge.
    If in addText has to hand over the result that exists at the time of the BeginInvoke challenge, line

    f.BeginInvoke(new Action(() => addText(f, result) ));
    

    should be replaced by

    f.BeginInvoke(
       new Action<string>(v => addText(f, v)), 
       result.ToString()    // передается в v в момент вызова делегата
       );
    

    That's the reference to Form, and we know that it's not gonna change, we don't need to transfer it to BeginInvoke.
    When working with locks, the rule should be observed: variables that may change at the time of the delegate &apos; s call shall be transferred to BeginInvoke when called


    Instead of calling BeginInvoke in different parts of the code, BeginInvoke can be transferred to addText and summoned after InvokeRequired.

    void addText(Form frm, int res) {
      if (frm.InvokeRequired)    // true - если вызван не из UI-потока
         frm.BeginInvoke(
            new Action<Form, int>((f, r) => addText(f, r)),
            frm, res);   // передается в (f, r)
      else
         frm.Controls.Add(new TextBox() { Text = res.ToString(), Dock = DockStyle.Top });
    }
    

    var f = new Form();

    f.Load += (s, e) => {
    Task.Run(() => {
    for (var result = 0; result< 5; result++)
    addText(f, result);
    });
    };

    f.ShowDialog();

    Although the addText method defines the challenge addText, it is. Not a class.e.g. BeginInvoke adds the delegate along with the data in a special turn that is processed in UI-stream.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2