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.
Apply one of the following attributes to your custom control, depending on which kind of data binding you need:
ComplexBindingPropertiesAttribute
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:
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; }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With