I have following situation in a C# Windows Forms (.NET 4.0) application:
I have a bindingsource which datasource is set to a collection of objects of a custom class.
Most properties of this class can be represented by a textbox or checkbox, as they are strings or numbers or bools.
However, there is one property, called Ratings, which is another custom object and must be represented by a custom control I developed.
I have bound a datagridview to the bindingsource, and obviously the dgview displays the numbers, strings and bools correctly. But on the same form I also have an instance of the custom control I developed, and so want I want to do now is bind my custom control to the same bindingsource as the datagridview uses, and to the specific datamember called Ratings. But I don't have the slightest clue on how to start. I suspect I must implement some interface which implements DataSource and DataMember on my control, but not sure where to begin. So basically what I want is each time the selected item is changed by means of selecting another row in the datagridview, the according Ratings property is represented in the custom control.
Right now the endresult that I wish to achieve is working, but I do this by refreshing my custom control each time the OnSelectedRowChanged event of the datagridview is firing, and associating the Ratings property of the selected item to the custom control.
But I was wondering if I could achieve this purely by the databinding mechanism in .NET.
Thanks for any replies !
Mathieu
ps: to further clarify, as it doesn't seem so clear in pure text:
Psuedo-code representing the object that I use as datasource for the bindingsource is:
public class Car
{
private string number;
private string name;
...
private Ratings ratings;
public string Number
{
get { return this.number; }
set { this.number = value; }
}
public string Name
{
get { return this.name; }
set { this.name = value; }
}
...
public Ratings Ratings
{
get { return this.ratings; }
set { this.ratings = value; }
}
}
So I want all the string and number properties from the bindingsource to bind to the datagridview, but I need the Ratings property to bind to the custom control.
I understood that you'd like to have a special column in the DataGridView with your custom control. To do this, you need to create a subclass of DataGridViewCell and DataGridViewColumn and implement IDataGridViewEditingControl.
See MSDN for an example.
You can read this Microsoft article about interfaces related to data binding. The ones of your interest are at the bottom under "Interfaces for Implementation by Component Authors" section.
Related
I have an object something like this:
public class Item
{
public string Name;
public int Id;
public int Quantity;
public decimal Volume;
public decimal Cost;
}
I'm wanting to create a reusable user control which would take a list of these objects and display them in a datagrid. The trick is that I want to specify which of the properties are shown in the datagrid for each instance of the control. Unfortunately my WPF skills are not up to the tasks and I don't want to create a specific control for each combination that I will want to use, as that feels like a lot of work for very similar code items. Any help to pointers of how to accomplish this would be greatly appreciated.
You can use the Columns property of your datagrid to interact with the columns and hide the columns you don't want.
datagrid.Columns.RemoveAt(IndexOftheColumn);
or if you named your columns
datagrid.Columns.RemoveAll(x => x.Name = "column name");
or if it is possible that you will need to column later
datagrid.Columns[IndexOftheColumn].Visibility = Visibility.Collapsed;
It is also possible to do this with pure Xaml with bindings but since you are new to Wpf I would suggest doing it in the code behind (the .cs of your Wpf control) first.
As for selecting which columns to hide you can pass a list of names for the columns you want to remove in the constructor of the control or with a binding. There are a lot of ways to do it.
Or you could do the opposite and add columns dynamically based on your needs.
Note that this question has been asked before
I have a normal data binding situation where my underlying question object properties are bound to columns in a devexpress XtraGrid.GridControl. However, I have one text property that takes the form of "{Question|True},{Question|False}". These must be mapped to checkboxes in the grid (potentially many per property). Is it possible to use data binding to bind this string property directly to a cell, providing checkbox editing, perhaps using a CheckedComboBox? I'm thinking I'd need an intermediate step in the binding process to map the original string to checkboxes, and then from the checkboxes back to the string.
Otherwise my current thinking is to create another layer of objects, which contains a new object for each of the checkbox options, but if I could somehow interrupt the default binding process with a mapping from the above text to the checkboxes in a CheckComboBox I'd be able to bind straight to the underlying objects.
If I understood you well I think that you should change your question object
to contain bool property. Bool properties are bound to grid as checkboxes, so it will work automatically.
I know that your real value of that property should be string "{Question|True}"
so you can set that property in that way:
private string question;
private bool questionBool;
public bool QuestionBool{
get{return questionBool;}
set{
if(value)
question = "{Question|True}"};
else
question = "{Question|False}";
questionBool = value;
}
I ended up converting the text into a collection of CheckboxQuestionAndAnswer objects which I then bound to the grid, then converting them back into a single text string for writing the data back.
I have a DataGridView and I'm binding it directly to a generic List of a custom class, no BindingSource intermediary. This custom class has a number of public properties and I want my dataGridView to display only some of those properties.
I've created datagridview columns for the custom class properties I'm interested in, and set their DataPropertyName to the class properties names. But the gridview fetches all the properties from its source and displays them.
Is there anyway to display only those properties I'm interested in?
Use
[System.ComponentModel.Browsable(false)]
public int SomeProperty{get;set;}
in your class.
Yes, set AutoGenerateColumns = false, then manually populate columns. or use
Browsable(false) attribute in columns which you don't want to show.
C#, VS-2010, winforms
Generally I want to create user control with a bindable MyProperty. But I met some problem: Data row become modified when current row changed.
You can download C# project and try it yourself:
test_bind.zip
To make it simple I did follow:
create test form with a
dataGridView (set it ReadOnly),
TextBox,
some typed DataSet with some Table
bindingSource
bind bindingSource to the table
bind dgv to bindingSource
bind TextBox.Text to bindingSource to some text column ("name")
on form load fill table with some data. (If you add rows manually do not forget AcceptChanges())
add event handler for table xxx_ColumnChanging(...) and set breakpoint there
all standard steps, nothing special
Run
as expected - rows in dgv, current name in textBox, click on different rows in grid...
and only when I modify text in textbox I stop in breakpoint.
Lets modify program, and bind textBox to different property instead of Text - lets say Tag.
Set DataSourceUpdateProperty "OnValidation" or "OnPropertyChanged".
Run
Now current row become modified. !!!
Same happens when instead of textBox I use UserControl with a dummy property
String MyProperty { set; get; }
How to bind custom property in user control with the same behaviour as TextBox.Text?
Note:
Binding property itself is not a problem. Problem is: when I bind to standard TextBox.Text property - everything Ok Wen I bind to ANY OTHER property (Tag) or to custom Property in User Control - then DATASOURCE ALWAYS BECOME MODIFIED FOR CURRENT ROW
Short answer is:
When bind to simple property, declared like
[Bindable(true, BindingDirection.TwoWay)] // I need TwoWay
public String MyProp {set;get;}
then datasource will be updated on current position change. You may count it as Bug or Feature...
To change behavior - I need magic word. Declare event in the control as
public event System.ComponentModel.PropertyChangedEventHandler MyPropChanged;
This name is special: "YourPropertyName" + "Changed" = YourPropertyNameChanged
Other word will not be magic.
As soon as event declared - datasource would not be updated every time as before...
and now I can control the process...
public void OnMyPropChanged(System.ComponentModel.PropertyChangedEventArgs e)
{
Binding bb = this.DataBindings[0] as Binding;
bb.WriteValue();
if (MyPropChanged != null) MyPropChanged(this, e);
}
private void TxtChanged(object sender, EventArgs e)
{
if (load) { return; }
_my_prop = Txt.Text; // ...
OnValueTwoChanged(new PropertyChangedEventArgs("MyProp"));
}
Here is the example project with more details, where I create user control with String property ValueTwo
which split in two different TextBoxes using some custom logic, and combine value and update when user change the text.
test_bind_fixed.zip
And this is article which help me
http://support.microsoft.com/kb/327413
Hi how do i pass in a class object from UI Form to the user control datagridview?
I created a user control which it has a datagridview, a search textbox on top of datagridview, and a label to show total count. and i would like to have the following feature to be written in that control.
Show Total count for that object bounded to datagridview.
TextChange event to filter the data in datagridview.
I would like the above features to be written in Usercontrol as i felt it is redundant to repeat that in UI Form.
For this, I created a datasource in the usercontrol
public object Datasource { get; set; }
1) If my class object is e.g. User, how do i get the type of the datasource converted to User and get the Count of total User and bind to the label in the usercontrol?
2) I felt it redundant to write this below in every form. How do i simplify this and make this run in the userControl itself by using the datasource i pass in to it.
private void BaseCRUDForm_GridViewTextChangedSearch(object sender, EventArgs e)
{
if (sender.ToString().Length > 0)
{
Users = Users.Where(x => x.Name.StartsWith(sender.ToString())).ToList();
}
else
{
Users = Repository.UserRespository(false).GetAllUsers();
}
UserBindingSource.DataSource = Users;
}
Please advice.
While creating the object of user control, There are two ways to forward the data in user control
Initialize the property. The Property will have the object type which can be cased later while binding to grid.
pass the data to constructor.
I feel that you should have constructor i.e point 2.
Now after casting this object, you can populate the label as well as the grid.
I hope this will help you.