0

In the example below, when the Tag1_changed and Tag2_changed methods are invoked, they require the form to be invoked to update a control or else an exception is thrown. However, when using the lambda method for the callback parameter, this.InvokeRequired evaluates to true but the control is still updated and no exception is thrown even though no MethodInvoker for the form is used. Why doesn't the (pnlHeartbeat.BackColor) statement throw an exception when executed?

private void BtnSubscribe_Click(object sender, EventArgs e)
    {
        var task = AppGlobals.opc.SubscribeToTagAsync("k_Tag1", Tag1_changed);
        task = AppGlobals.opc.SubscribeToTagAsync("k_Tag2", Tag2_changed);
        task = AppGlobals.opc.SubscribeToTagAsync("k_Heartbeat", (tagname, tag) =>
        {
            try
            {
                bool ir = this.InvokeRequired;  //this is always true
                pnlHeartbeat.BackColor = tag.Value.ToBooleanOrDefault(false) ? System.Drawing.Color.Green : System.Drawing.Color.Red;  //value updates fine without exception
            }
            catch (Exception ex)
            {
                string exm = ex.Message;  //never gets here even though InvokeRequired is true
            }
        });

    }

    private void Tag1_changed(string tagname, DataValue tag)
    {
        this.BeginInvoke(new MethodInvoker(() =>
        {
            lblTag1Value.Text = tag.Value.ToString();
        }));
    }

    private void Tag2_changed(string tagname, DataValue tag)
    {
        this.BeginInvoke(new MethodInvoker(() =>
        {
            lblTag2Value.Text = tag.Value.ToString();
        }));
    }

SubscibeToTagAsync method signature is:

public async Task SubscribeToTagAsync(string tagname, Action<string, DataValue> callback)

The callback Action is stored away in an OnChange property and eventually executed in the following way:

this.Tags[tag.Key].OnChange?.Invoke(tag.Key, mon.Value);
Steve B.
  • 1
  • 1
  • The crux of the matter is determining what thread invokes that callback. The method name suggests things based on `async`/`await`, in which case it probably is on the UI thread already. – Ben Voigt Feb 07 '18 at 21:54
  • Glad you noticed this though, because it will break you out of the cargo cult programming mindset and lead you to actual understanding. – Ben Voigt Feb 07 '18 at 21:55
  • This exception is only enabled when a debugger is attached and is a heuristic that is not 100% reliable. It is not for the BackColor property, updating it from a worker thread is in fact thread-safe. Usually. Underlying behavior is that it only marks the control in need of repainting through the Invalidate() method, the actual paint occurs later and always runs on the UI thread. http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,7255 – Hans Passant Feb 07 '18 at 22:02

0 Answers0