Binding with object in Windows forms designer - c#

I am trying to bind a list in my namespace to BindingSource through designer. I know how to bind a list in code behind but I would also like to know if it is possible to do the same in designer.
Using the "Data Source Configuration Wizard", I have selected "Object" but it shows only namespace and classes.
I choose a class with List and clicked Finish.
This is the code generated in designer after choosing the class name
this.bindingSource1.DataSource = typeof(Template.Form3);
It looks like windows forms does not have support for binding a list in designer. I am not sure this is the right method or windows forms does not support it. If windows forms have no support for binding to an object, can anyone explain the reason?
Edit:
I tried the suggestion in answer to choose a data member, but it does not bind the binding source with actual data in List. Now designer code looks like
this.bindingSource1.DataMember = "data";
this.bindingSource1.DataSource = typeof(Template.Form3);

The trick is to rebuild your solution, then any public class will be visible in the dropdown list to choose the datasource type from.
Then from the designer, click the binding source (bottom of screen) => Properties => DataMember => Select Property in your class to bind to (A List or Collection)
Edit:
Binding through the designer allows generation of columns at Design time, but it seems that you need to set the BindingSource's Data at runtime.
Since the bind object can't be static memeber but instance member.
private void bindingForm_Load(object sender, EventArgs e)
{
myDataSourceBindingSource.DataSource = (new myDataSource()).MyDataSourceList;
}
Designer:
//
// colADataGridViewTextBoxColumn
//
this.colADataGridViewTextBoxColumn.DataPropertyName = "ColA";
this.colADataGridViewTextBoxColumn.HeaderText = "ColA";
this.colADataGridViewTextBoxColumn.Name = "colADataGridViewTextBoxColumn";
//
// myDataSourceBindingSource
//
this.myDataSourceBindingSource.DataMember = "MyDataSourceList";
this.myDataSourceBindingSource.DataSource = typeof(myNameSpace.myDataSource);
Class:
public class myDataSource
{
public BindingList<myData> MyDataSourceList
{
get
{
var list = new List<myData>()
{
new myData() { ColA = "A" },
new myData() { ColA = "B" }
};
return new BindingList<myData>(list);
}
}
}
public class myData
{
public string ColA { set; get; }
}
I don't know if this makes sense for you, but this is how it works in Windows Forms.

Related

ToolStripButtons of a custom BindingNavigator appear locked in the Form Designer

I'm trying to create a custom BindingNavigator control in with some extra ToolStripButton (Edit and ExportToExcel).
The ToolStripButton is added to the BindingNavigator, but I cannot select this new ToolStripButton, e.g., to add code in its Click event handler. Actually, the ToolStripButtons appear locked.
Here is my code and an image that should describe the problem:
using System.Windows.Forms;
public class BindingNavigator : System.Windows.Forms.BindingNavigator
{
public ToolStripButton btnEdit;
public ToolStripButton btnExcelExport;
public BindingNavigator()
{
this.LayoutCompleted += BindingNavigator_LayoutCompleted;
}
public void BindingNavigator_LayoutCompleted(object sender, System.EventArgs e)
{
if (this.Items.Contains(btnEdit))
return;
if (this.Items.Count >= 11)
{
btnEdit = new ToolStripButton();
btnEdit.Image = global::BaseControls.Properties.Resources.Edit___16x16;
btnEdit.Name = "btnEdit";
this.Items.Insert(10, btnEdit);
this.Items.Add(new ToolStripSeparator());
btnExcelExport = new ToolStripButton();
btnExcelExport.Image = global::BaseControls.Properties.Resources.Excel___16x16;
btnExcelExport.Name = "btnExcelExport";
this.Items.Insert(13, btnExcelExport);
}
}
}
The BindingNavigator class has a dedicated Designer, BindingNavigatorDesigner, derived from ToolStripDesigner.
The Designer calls the public virtual AddStandardItems() method, which is then called by Form Designer when a BindingNavigator is added to a Form.
To make your Buttons functional, override this method in a custom class and add new buttons here.
Now your ToolStripButtons are serialized in the Form Designer and, if you double-click one of your custom buttons, a Click handler is added to the Form.
Notes you can find in the .Net Source Code:
Override this method in derived classes to define additional or
alternative standard items. To ensure optimal design-time support
for your derived class, make sure each item has a meaningful value in
its Name property. At design time, this will be used to generate a
unique name for the corresponding member variable. The item's Name
property will then be updated to match the name given to the member
variable.
As you can see, now the buttons are fully functional
I suggest you modify your custom BindingNavigator like this:
▶ Don't name your Custom Control BindingNavigator
public class BindingNavigatorEx : BindingNavigator
{
private ToolStripItem btnEdit;
private ToolStripItem btnExcelExport;
public BindingNavigatorEx() { }
public override void AddStandardItems()
{
base.AddStandardItems();
Items.Add(new ToolStripSeparator());
btnEdit = new ToolStripButton() {
Image = Properties.Resources.Edit___16x16,
Name = "bindingNavigatorButtonEdit",
DisplayStyle = ToolStripItemDisplayStyle.Image
};
Items.Add(btnEdit);
btnExcelExport = new ToolStripButton() {
Image = Properties.Resources.Excel___16x16,
Name = "bindingNavigatorButtonExcelExport",
DisplayStyle = ToolStripItemDisplayStyle.Image
};
Items.Add(btnExcelExport);
}
}

How to bind container of custom objects at design-time

I want to have a container of objects that will be visualised in WinForms' DataGridView control.
As far as I know, I can bind a container to DataGridView via the DataSource property.
But I wonder, is there any way to do it in Designer? I see a lot of options related to that (like DataSource, DataMember etc) but I don't see any option that will give me a possibility to choose my own container inside the Form class.
I don't want to make this kind of stuff programmatically if it's available in the designer.
DataSource is bindable in designer. You can press the little arrow at the top of the DataGridView, and Choose Data Source. At the bottom> Add Project DataSource...
After adding the class, that will contain Your DataSource, You can set in the properties pane which public property is Your DataSource.
For example:
public class ThereIsDataSourceInThisClass
{
public ThereIsDataSourceInThisClass()
{
MyDataSource = new BindingList<Thing>();
MyDataSource.Add(new Thing { First = "aa", Second = "bb" });
}
public BindingList<Thing> MyDataSource { get; set; }
public class Thing
{
public string First { get; set; }
public string Second { get; set; }
}
}
I selected ThereIsDataSourceInThisClass in the wizard, than I selected MyDataSource in the DataSource property.
The result is>

Create a simple DataGridView with List of objects and checkbox column (C#)

I have looked at a lot of places and I'm struggling to do this supposedly simple thing. I have a Windows form on which I've to show a simple DataGridView in this form:
| (CheckBoxColumn) | FilePath | FileState |
Now, there are a couple of problems. The data I need to bind to them is in a List of objects like this:
class FileObject
{
string filePath;
string fileState;
}
//Now here's the list of these objects which I populate somehow.
List<FileObject> listFiles;
Is there any efficient way to bind this directly to the DataGridView
so that different members of Object in the list are bound to
different columns, and for each there's checkbox?
I saw the examples of adding checkbox column to a datagrid, but none of them showed how
to add it to the 'header' row as well, so that it can behave as a 'check all'/'uncheck all' box.
Any help in how to achieve this would be great! I do write simple applications in C# but never had to work with datagrids etc. :(
Thanks!
The DataGridView control has a feature to automatically generate columns that can be set by the AutoGenerateColumns property. This property defaults to true - that is columns are by default auto generated.
However, columns are only automatically generated for public properties of the object you bind to the grid - fields do not show up.
Auto generation also works for check box columns when there is a public boolean property on the bound object.
So the simplest way to achieve your first two requirements is to change your FileObject class to this:
public class FileObject
{
public string FilePath { get; set; }
public string FileState { get; set; }
public bool Selected { get; set; }
}
If you cannot modify that class then next best would be the create a wrapper object that holds a file object:
public class FileObjectWrapper
{
private FileObject fileObject_;
FileObjectWrapper()
{
fileObject_ = new FileObject();
}
FileObjectWrapper(FileObject fo)
{
fileObject_ = fo;
}
public string FilePath
{
get { return fileObject_.filePath; }
set { fileObject_.filePath = value; }
}
public string FileState
{
get { return fileObject_.fileState; }
set { fileObject_.fileState= value; }
}
public bool Selected { get; set; }
}
You can then create your list to bind to (a BindingList is usually best) doing something like:
var fowList = new BindingList<FileObjectWrapper>();
foreach (FileObject fo in // here you have your list of file objects! )
{
fowList.Add(new FileObjectWrapper(fo));
}
dataGridView1.DataSource = fowList;
There are many ways to do the above but that is a general idea.
You can also add an unbound DataGridViewCheckBoxColumn to the grid, though I find it easier to have in the the bound list. Here is how if you do need to:
DataGridViewCheckBoxColumn c = new DataGridViewCheckBoxColumn();
c.Name = "Selected";
dataGridView1.Columns.Add(c);
Finally, for having a "SelectedAll" option in the header you will need to use custom code.
The article on CodeProject that Umesh linked to (CheckBox Header Column for DataGridView) looks quite easy to implement - they create a custom DataGridViewHeaderCell overriding the Paint and OnMouseClick methods.
Please refer the the below example, showing exactly what you are looking for
http://www.codeproject.com/Articles/20165/CheckBox-Header-Column-For-DataGridView

Telerik Radgrid hierarchical detail grid edit not updating binding list

I need some help here. Here is my situation:
I have a binding list which contains another binding list which I use as data source. below is an example:
Objects:
public class test
{
public string name { get; set; }
public BindingList<childs> childlist { get; set; }
}
public class childs
{
public string childname { get; set; }
}
I populate my radgrid by code. below is a preview:
private void form_Load(object sender, EventArgs e)
{
BindingList<test> testlist = new BindingList<test>();
/** I populate my list with data. I wont show this here. After the list is populated: **//
this.raggrid.MasterTemplate.Columns.Clear();
this.raggrid.MasterTemplate.AutoGenerateColumns = true;
this.raggrid.MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
this.raggrid.MasterTemplate.Columns.Add(new GridViewTextBoxColumn("name", "name"));
GridViewTemplate template = new GridViewTemplate();
this.raggrid.Templates.Add(template);
template.Columns.Add(new GridViewTextBoxColumn("name", "childname"));
template.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
GridViewRelation relation = new GridViewRelation(this.raggrid.MasterTemplate, template);
relation.ChildColumnNames.Add("childlist");
this.raggrid.Relations.Add(relation);
this.raggrid.DataSource = testlist;
}
The populating step works fine. But now, when the user edits the detail grid(named template from the code), I must update the binding list accordingly (named testlist from the code). I cannot seem to trigger an event when I edit the child grid. How do I achieve this?
Note: This is a winform application
PS: When I update the master template the binding list gets updated automatically as expected, but when I update the template I use as detail, it does not update the biding list.
Thanks,
Yash
For anyone having a similar problem, here is the solution:
Solution
Only thing is that I used CellValueChanged event instead of RowsChanged.

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.
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; }
}
}
Your class needs to inherit the DataBoundControl class instead of UserControl.
To run the very helpfull example of Chris Tollefson BindingDemo without problems put a try/catch Block around the LookupMember getter like this:
public string LookupMember {
get {
try {
return listBox1.SelectedValue.ToString();
}
catch { return null; }
}
set => listBox1.SelectedValue = value;
}

Categories

Resources