Good Day,
I am trying to make a custom control where a property can be bound to a DataSource. I have been searching all day and managed to figure out how to set the custom control DataSource to the desired DataSource on my form. I also saw how to set the values of a ComboBox. But I will be using a GroupBox.
For example, in a ComboBox control we have the properties - DataSource, DisplayMember and Value Member. And the value of the column can be found with "NormalComboBox.SelectedValue".
How will I be able to bind my custom "ValueMember" property to a column in my binding source in order to get the value of the column in the current row?
public class ValueGroupBox : GroupBox
{
private object _dataSource;
// ** This is where I am having issues - Need to return value
private string _valueMember;
private string _selectedValue;
public string ValueMember { get { return _valueMember; } set { _valueMember = value; }
public string SelectedValue { get { return _selectedValue; } set { _selectedValue = value; }
// ** End of having trouble
[Category("Custom Data")]
[Description("Indicates the source of data for the GroupBox control.")]
[TypeConverter("System.Windows.Forms.Design.DataSourceConverter, System.Design")]
[DefaultValue(null)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public object DataSource
{
get
{
return this._dataSource;
}
set
{
if (this._dataSource != value)
{
this._dataSource = value;
}
}
}
}
Any help would be much appreciated.
Related
I've a custom-made user control:
public class CustomUC : UserControl
{
[Bindable(true)]
private string PropertyX { get { ... } ; set { ... }; }
}
I'm using it from another form. On this form I'm using a DataSource.
The problem is that I'm unable to figure out how to bind this PropertyX to some field of my DataSource.
EDIT
My DataSource is a System.Windows.Forms.BindSource object I've created on design-time. I've set a class to this datasource in order to be linked to a ClassA. This class has a property Notes I'd like to bind to CustomMadeUCPropertyX...
You should try following way to bind property by coding:
object.DataBindings.Add("PropertyX", YourDataSrouce, "columnname in your datasource")
I have created my custom UserControl with some custom properties for it. For example:
[Description("Example Description"),Category("CustomSettings"),DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get; set;
}
Everything works fine. I can change custom property in code and in design-time.
What I'm looking for (and cannot find anything) now is: How could I repaint (reacreate) my UserControl in design-time when my custom property change in design-time.
Let's say when DatabaseName will be changed to localhost UserControl will add and display some Label on my UserControl. It's important to work in Design-Time.
Nothing special there. You just have to set the text to Label inside the property setter. That should update the UI.
private string databaseAddress;
[Description("Example Description"), Category("CustomSettings"), DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get { return databaseAddress; }
set
{
databaseAddress = value;
yourLabel.Text = value;//Set value to Label or whatever
}
}
Try this
private string _databaseAddress = "localHost";
[Description("Example Description"), Category("CustomSettings"), DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get
{
return _databaseAddress;
}
set
{
if(!string.IsNullOrEmpty(value))
{
_databaseAddress = value;
lblAddress.Text = value;
lblAddress.Invalidate();
}
}
}
Both previous answers are correct.
I just want to add that the user control can even react on resizing during design time, using the Layout event.
I have a datagrid bound to an ObservableCollection<MyClass>, and I have another datagrid which has two DataGridTextColumns - Name and Value. The Name column is prepopulated with the names of properties whose values should be displayed in the Value column. MyClass implements INotifyPropertyChanged, so any change in the properties of MyClass objects updates the first datagrid. Now, I would like to display the properties of the currently selected object (SelectedItem) of the first datagrid in the Value column of the second datagrid and see the property changes as they happen, like in the first datagrid. How can I accomplish this?
If you wonder about the reason, only some of the properties are displayed in the original datagrid, so the other one should display almost all of them. Is datagrid even a good choice for displaying properties in 2 columns or should I consider some other control?
This sounds like one convenient solution to a fairly common problem.
The easiest way to do this with two data grids will be for you to use some code behind and reflection. First define a type to display the Name and value of each property:
class PropertyModel {
private readonly string _name = "";
private readonly object _value = null;
public PropertyModel(string name, object value) {
_name = name ?? "";
_value = _value;
}
public string Name {
get { return _name; }
}
public object Value {
get { return _value; }
}
}
Then add an event handler to your code-behind to handle selection changes on your first datagrid:
private void _onDataGrid1SelectionChanged(object sender, SelectedCellsChangedEventArgs e) {
if (e.AddedCells.Count > 0) {
var props = new Collection<PropertyModel>();
var obj = _dataGrid1.SelectedItem;
foreach(var prop in obj.GetType().GetProperties()) {
props.Add(new PropertyModel(prop.Name, prop.GetValue(obj, null)));
}
_dataGrid2.ItemsSource = props;
}
}
Note that the code above is very rough, and will only work if DataGrid1 has SelectionMode set to Single. However this is a good place to start, if you are willing to do it quick and dirty (with an event handler).
Another great solution is to use row details.
This is a pretty good intro tutorial on using row details.
Of course you should also read the msdn article on the subject.
This is part of my AOI class (nothing special about it):
class AOI : INotifyPropertyChanged
{
private Guid _id;
private string _name;
private string _comment;
public Guid Id
{
get { return _id; }
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public string Comment
{
get { return _comment; }
set
{
_comment = value;
OnPropertyChanged("Comment");
}
}
public override string ToString()
{
if (_name.Length > 0)
{
return _name;
}
else
{
return _id.ToString();
}
}
}
I keep them in a BindingList<AOI> which is bound to a ListBox. In the SelectedValueChanged event of the ListBox I assign the selected object to a PropertyGrid, so that the user can modify the AOI.
This works fine except for the Name field (which is displayed in the ListBox (see ToString() above)).
When I edit the name field using the PropertyGrid, the ListBox is updated correctly. But in the PropertyGrid, the Name field (just the value) is cleared as soon as I press enter. The correct (modified) value appears when I set the cursor to another field in the PropertyGrid.
What is the easiest workaround to handle this correctly?
This is a problem of the PropertyGrid.
This can also be reproduced with the designer within the Visual Studio. Simply select a control and change its minimum size to a larger value than the current one. If you take a look into the grid, the value in the size property won't be updated till you select it within the grid.
If some rows won't update correctly normally one of these two options will help:
Reattach the object to the PropertyGrid by calling propertyGrid.SelectedObject = myObject
Force the grid to redraw itself by calling propertyGrid.Invalidate()
Is there a way to determine the order of the columns displayed in
a datagridview when binding it to a datasource whitch contains an
underlying IList ?
I thought there was a specific property attribute for this purpose
but can't recall what it actually was.
eg:
public void BindToGrid(IList<CustomClass> list)
{
_bindingSource.DataSource = list;
dataGridView1.DataSource = _bindingSource.DataSource;
}
Type binded should be something like this
class CustomClass
{
bool _selected = false;
//[DisplayOrder(0)]
public bool Selected
{
get { return _selected; }
set { _selected = value; }
}
string _name;
//[DisplayOrder(2)]
public string Name
{
get { return _name; }
set { _name = value; }
}
string _value;
//[DisplayOrder(1)]
public string Value
{
get { return _value; }
set { _value = value; }
}
}
Edit:
I would like to add that I rather not want to add the columns manually to columns list in the designer. I'd like to keep this as dynamic as possible.
In the DataGridView specify an actual list of columns instead of allowing it to auto-databind. You can do this in Design View in Visual Studio by selecting the control and adding the columns. Make sure you specify in each column which property it should bind to. Then you can rearrange the columns any way you want as well as do other customizations.
I think that the DisplayOrder attribute is relatively new and probably not supported in the DataGridView control.
The display order of the columns in the DataGridView is determined by the DisplayIndex properties of the DataGridViewColumn-s. You would have to set these properties on the columns of the grid, in order to change their order.
I also agree with Eilon's answer: you can create the list of the columns yourself, instead of auto-databinding, and that way you can determine the order in which they will be displayed.
The column ordering does not always work. You'll need to turn off AutoColumnCreate to fix inconsistencies:
http://www.internetworkconsulting.net/content/datadridview-displayorder-not-working
I am not sure whether this is a functionality that .Net Offers, but if you just change the order of your properties in the class, the grid renders the columns in the same order.
The below two classes will render in the order they are typed in the class. Strange!!
class CustomClass
{
public bool Selected {get;set;}
public string Name{get;set;}
}
class CustomClass
{
public string Name{get;set;}
public bool Selected {get;set;}
}