question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[API Proposal]: Allow `Control.Invoke` on `Binding`

See original GitHub issue

Background and motivation

Bindings allow for Form Controls and models to be updated when their values are changed by the system in any way. This would allow the form to be reactive, with processes running in the background performing all the necessary actions and having them reflected by the bindings automatically.

This already works with MAUI, specially if you use the CommunityToolkit.Mvvm and its generators. However, while Winforms support bindings as well, it does not support asynchronous updates, because doing so would raise a InvalidOperationException.

This happens because the Binding class updates the value of the property directly, without checking if the control is in the UI Thread or not.

I then propose a new constructor to the Binding class in which you can set a flag to prefer using Control.Invoke when updating the bindings. Control.Invoke forces the Action to run at the UI Thread, solving the problem.

I have already opened an issue about this as well as a PR.

API Proposal

namespace System.Windows.Forms;

public class Binding
{
    public Binding(string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, object nullValue, string formatString, IFormatProvider formatInfo, bool invokeControl);
}
namespace System.Windows.Forms;

public class ControlBindingsCollection : BindingsCollection
{
    public Binding Add(string propertyName, object dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode updateMode, object nullValue, string formatString, IFormatProvider formatInfo, bool invokeControl);
}

API Usage

// Create a new form and a text box to bind values to
Form form = new Form();
TextBox textBox = new TextBox();
textBox.Parent = form;

// Create a binding to handle the invoke method
Binding binding = new Binding("Text", mainObject, "Text", false, 0, null, string.Empty, null, true);
textBox.DataBindings.Add(binding);

form.Show();

// Perform the binding update in a separate thread to escape the UI Thread on purpose
var thread = new Thread(() =>
{
    textBox.Text = "Updated test text";

    Assert.Equal("Updated test text", textBox.Text);
    Assert.Equal("Updated test text", mainObject.Text);
});

thread.Start();

Alternative Designs

I have added a new constructor to the System.Windows.Forms.Binding class and a new public method to System.Windows.Forms.ControlBindingsCollection without changing previous APIs.

Risks

In my limited study of the APIs, I didn’t see any breaking risk associated with this proposal. There may be performance repercussions in the Control.Invoke mechanic on heavy load but I was unable to test it.

The PR I mentioned has some tests which could be useful in analyzing those scenarios.

Issue Analytics

  • State:open
  • Created 7 months ago
  • Comments:14 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
KlausLoeffelmanncommented, Feb 24, 2023

Just a quick update: We’re still very much considering this but need to address a couple of higher priority issues, first.

1reaction
zeh-almeidacommented, Feb 8, 2023

I am in the process of building a better example as I only have my code to show for, which wasn’t crafted for this case specifically.

Yes, we are talking about INotifyPropertyChanged derived objects, specifically when you have a asynchronous operation on said object which triggers the event.

I have a previous example here from my project, which illustrates how I was creating the binding.

However, because of my message is asynchronous, some of the message handlers changed their properties and the binding raised the System.InvalidOperationException.

Hope this clarifies the issue better.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Introduce InvokeAsync on Control · Issue #4631
I assume that Invoke is used by the framework to handle events internally, like closing a Window, calling to repaint, etc., (events which...
Read more >
How to use parameter binding in minimal APIs in ASP.NET ...
Parameter binding involves mapping incoming HTTP request data to action method parameters, allowing developers to process requests and respond ...
Read more >
c# - Invoke(Delegate)
This Invoke method allows you to execute methods in the associated thread (the thread that owns the control's underlying window handle).
Read more >
c# - How do I update the GUI from another thread?
You'll need to Invoke the method on the GUI thread. You can do that by calling Control.Invoke. For example: delegate void UpdateLabelDelegate ( ......
Read more >
Control.Invoke Method (System.Windows.Forms)
The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found