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
Related
I make an application by C# and WPF technology.
I have a method to update my Datagrid content:
dgContact.ItemsSource = db.ContactRepository.GetAllContact();
after every add or update, I call this method.
if I add a record, a new record shown in my grid.
but if I update a record, changes not be displayed in my grid (changed in DB).
how I can update Datagrid content by last data in DB?
thanks
It depends on the type of structure that your method returns.
If your method returns a non-ObservableCollection, what you can do is before setting DataGrid.ItemsSource to your method, set DataGrid1.ItemsSource = null; In this way, you are telling the WPF system that there was a change and that your DataGrid will be updated, like this:
private void Update_OnClick(object sender, RoutedEventArgs e) {
this.DataGrid1.ItemsSource = null;
this.DataGrid1.ItemsSource = db.ContactRepository.GetAllContact();
}
On the other hand, if your method returns an ObservableCollection, just set the ItemsSource property the way you did it before, and the WPF system will detect the change.
Check this project so you could verify it.
You can Bind the DataDrid ItemSource to ObservableCollection, try to do your changes with the database then update the ObservableCollection and it notifies when a change has been made.
I have a Windows Form with a number of Textboxes. I bind them to a DataSource as the Form Loads.
public partial class FormSettings : Form
{
private readonly DbContext _context = new DbContext();
public FormSettings()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
_context.OrderEntrySettings.Load();
SettingsBindingSource.DataSource = _context.OrderEntrySettings.Local.ToBindingList();
Binding saNbinding = new Binding("Text", SettingsBindingSource, "InvoiceNumber");
InvoiceNumberTextBox.DataBindings.Add(saNbinding);
Binding pthNbinding = new Binding("Text", SettingsBindingSource, "SalesOrderExportPath");
PathTextBox.DataBindings.Add(pthNbinding);
<snip>
…
</snip>
}
One of the Textboxes is bound to a Directory Path (string) Property.
If I type in a new directory in the Path Textbox and hit my save button, The path saves just fine.
But, If I change the Text Property on the Textbox to the SelectedPath from a FolderBrowserDialog dialog and then hit save, the Textbox Text shows the directory I selected but the Entity is not modified and nothing gets saved back to the database.
As a workaround, I set both the Path Textbox Text and set the Property from the context to the SelectedPath.
Why does a Bound Textbox not modify its associated property if the Text value is set programmatically?
Here is the reason. Binding class has a property called DataSourceUpdateMode with 3 options - Never, OnPropertyChanged and OnValidation, the last being a default. When you set the Text property programatically, there is no validating/validated events because they fire only when the control is on focus and has been edited, so the binding does not update the data source.
That being said, here are the options you have:
(A) Do not set the control property programatically, set the data source property instead.
(B) Change the binding DataSourceUpdateMode to OnPropertyChanged. This however will cause the data source property to be updated on every char that the user is typing.
(C) Use the following snippet:
yourTextBox.Text = ...;
yourTextBox.DataBindings["Text"].WriteValue();
If memory serves, data binding in WinForms (and possibly WebForms) uses the changes in control focus to detect when the data in the field has changed.
When you are modifying the values of the controls in the code-behind, you generally aren't changing the control focus. Consequently, there isn't anything that pokes the data-binding engine in the ribs and clues it in to the fact that it needs to re-evaluate the data.
I have a TextBox to which I have given a DataBinding as follows:
txtCompanyAddress.DataBindings.Add("Text", CompanyDetailsDataSet,
"CompanyDetails.CompanyAddress");
Also I have added a BindingManagerBase object on form as below:
protected BindingManagerBase BindingManager
{
get
{
return this.BindingContext[CompanyDetailsDataSet, "CompanyDetails"];
}
}
I have a cancel button on my form which cancels the changes. When I update the value in txtCompanyAddress and hit cancel, I call BindingManager.CancelCurrentEdit(); but the text box value does not change to old one.
Is this any data bindings issue?
Your bindings will not refresh automatically with this setup you need to change the mode when data binding is updated
txtCompanyAddress.DataBindings.Add("Text", CompanyDetailsDataSet,"CompanyDetails.CompanyAddress", true,DataSourceUpdateMode.OnPropertyChanged);
Also you haven't posted what your CompanyDetailsDataSet is so i assume it implements IEditableObject interface. Otherwise you will have to do it on your own and ensure that old value is cached and retrieved on CancelEdit()
textBox1.DataBinding.Add("Text",ds.Tables[0],"ColumnName")
where ds is the object of DataSet and [0] is the number of table in dataset you can write the name of table in double codes in the place of 0 if your procedure returns more then one table...
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.
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.