WinForms data binding without properties

37 Views Asked by At

In WinForms, is it possible to databind without using properties?

I've got a class that has some properties that I can databind to, however it also has some user defined custom fields that are only available at runtime. e.g.:

public class Item
{
    public int Id { get; set; } // I can databind controls to this
    public string Name { get; set; } // I can databind controls to this

    public object GetCustomFieldValue(string customFieldName);
    public void SetCustomFieldValue(string customFieldName, object value);
}

Is there any way to hook into the binding logic to call the GetCustomFieldValue and SetCustomFieldValue methods instead of getting/setting properties?

I've tried creating a custom binding class that inherits from Binding with the hope of overriding some of the methods such as ReadValue() and WriteValue() but they're not virtual so that looks like a dead end.

Is there any other approach I could try?

1

There are 1 best solutions below

0
Daniel Smith On

Here's the solution I came up with in the end.

Create an interface for your custom fields:

public interface ICustomFields
{
    Dictionary<string, object> CustomFields { get; }
}

Make sure your classes that have custom fields implement the interface:

public class Item : ICustomFields
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Dictionary<string, object> CustomFields { get; set; } = new Dictionary<string, object>();
}

Finally, I created an extension method to simplify adding the data bindings:

public static void AddCustomFieldBinding(this ControlBindingsCollection bindings, string controlPropertyName, object dataSource, string customFieldName)
{
    Binding binding = new Binding(controlPropertyName, dataSource, null);
    binding.Format += (o, c) => c.Value = ((ICustomFields)c.Value).CustomFields[customFieldName];

    binding.Parse += (o, c) =>
    {
        Binding b = (Binding)o;
        BindingSource bs = (BindingSource)b.DataSource;
        ICustomFields i = (ICustomFields)bs.Current;
        i.CustomFields[customFieldName] = c.Value;
    };

    bindings.Add(binding);
}

Then assuming you've got a form with a BindingSource and a TextBox control that you'll data bind to, you can use the above code like this in your form's Load event:

private void MainForm_Load(object sender, EventArgs e)
{
    // Create an example Item with an additional custom field called "Notes"
    Item item = new Item() { Id = 1, Name = "Example item" };
    item.CustomFields["Notes"] = "Example notes";

    // Add the custom data binding using the extension method
    this.notesTextBox.DataBindings.AddCustomFieldBinding("Text", this.itemBindingSource, "Notes");

    this.itemBindingSource.DataSource = item;
}