Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add DataSource Property to a Custom WinForms Control

I want to add complex databinding to my custom winforms control, so I can do the following:

myControl.DisplayMember = "Name";
myControl.ValueMember = "Name";
myControl.DataSource = new List<someObject>();

Does anyone know what interfaces, etc. have to be implemented to achieve this?

I have had a look into it and all I found is IBindableComponent, but that seems to be for Simple Binding rather than Complex Binding.

like image 355
Corin Blaikie Avatar asked Oct 14 '22 18:10

Corin Blaikie


1 Answers

Apply one of the following attributes to your custom control, depending on which kind of data binding you need:

  • For complex data binding: ComplexBindingPropertiesAttribute
  • For lookup data binding: LookupBindingPropertiesAttribute

(The question specifically mentions complex data binding, but the given code example looks like lookup data binding to me, so I have included both.)

For example implementations, look at the .NET Framework source code:

  • ComplexBindindPropertiesAttribute implementation in DataGridView
  • LookupBindingPropertiesAttribute implementation in ListControl

But those implementations look very complicated to me, so it might be easier to embed an existing control (such as a DataGridView, ListBox or ComboBox) within your own custom control to take advantage of its existing data binding implementation, rather than writing your own. (You could make the embedded control invisible if necessary.) That is the approach demonstrated by Microsoft in the following guides:

  • Create a Windows Forms user control that supports complex data binding
  • Create a Windows Forms user control that supports lookup data binding

In those guides, they create a data source to bind the custom control to an external database, but it looks like you're simply trying to bind your custom control to an internal collection such as a List<T>. In that case, the adapted code below might work for you.


In a Windows Forms project in Visual Studio, add a new UserControl.

For complex data binding, apply the ComplexBindingPropertiesAttribute to the custom control. Add a DataGridView control to it. Add DataSource and DataMember properties, and hook them into the DataGridView's own properties.

// ComplexBindingControl.cs
// Adapted from https://learn.microsoft.com/visualstudio/data-tools/create-a-windows-forms-user-control-that-supports-complex-data-binding

using System.ComponentModel;
using System.Windows.Forms;

namespace BindingDemo
{
    [ComplexBindingProperties("DataSource", "DataMember")]
    public partial class ComplexBindingControl : UserControl
    {
        public ComplexBindingControl()
        {
            InitializeComponent();
        }

        // Use a DataGridView for its complex data binding implementation.

        public object DataSource
        {
            get => dataGridView1.DataSource;
            set => dataGridView1.DataSource = value;
        }

        public string DataMember
        {
            get => dataGridView1.DataMember;
            set => dataGridView1.DataMember = value;
        }
    }
}

For lookup data binding, apply the LookupBindingPropertiesAttribute to the custom control. Add a ListBox or ComboBox control to it. Add DataSource, DisplayMember, ValueMember and LookupMember properties, and hook them into the ListBox's or ComboBox's own properties.

// LookupBindingControl.cs
// Adapted from https://learn.microsoft.com/visualstudio/data-tools/create-a-windows-forms-user-control-that-supports-lookup-data-binding

using System.ComponentModel;
using System.Windows.Forms;

namespace BindingDemo
{
    [LookupBindingProperties("DataSource", "DisplayMember", "ValueMember", "LookupMember")]
    public partial class LookupBindingControl : UserControl
    {
        public LookupBindingControl()
        {
            InitializeComponent();
        }

        // Use a ListBox or ComboBox for its lookup data binding implementation.

        public object DataSource
        {
            get => listBox1.DataSource;
            set => listBox1.DataSource = value;
        }

        public string DisplayMember
        {
            get => listBox1.DisplayMember;
            set => listBox1.DisplayMember = value;
        }

        public string ValueMember
        {
            get => listBox1.ValueMember;
            set => listBox1.ValueMember = value;
        }

        public string LookupMember
        {
            get => listBox1.SelectedValue?.ToString();
            set => listBox1.SelectedValue = value;
        }
    }
}

(Edit: thanks to Frank's answer for reminding me that listBox1.SelectedValue could be null.)

To test it, build the project in Visual Studio, then add an instance of the custom control to a Form. Create some sample data, and bind it to the custom control using its relevant properties.

// Form1.cs

using System.Collections.Generic;
using System.Windows.Forms;

namespace BindingDemo
{
    public partial class Form1 : Form
    {
        private readonly List<SomeObject> data;

        public Form1()
        {
            InitializeComponent();

            // Prepare some sample data.
            data = new List<SomeObject>
            {
                new SomeObject("Alice"),
                new SomeObject("Bob"),
                new SomeObject("Carol"),
            };

            // Bind the data to your custom control...

            // ...for "complex" data binding:
            complexBindingControl1.DataSource = data;

            // ...for "lookup" data binding:
            lookupBindingControl1.DataSource = data;
            lookupBindingControl1.DisplayMember = "Name";
            lookupBindingControl1.ValueMember = "Name";
        }
    }

    internal class SomeObject
    {
        public SomeObject(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
    }
}
like image 169
Chris Tollefson Avatar answered Oct 18 '22 14:10

Chris Tollefson