Record Status or Detecting Value Changes
-
I've tried searching to see if this question has been asked before, but the search is not working for some reason. Does anybody know of an easy way to detect if a displayed record has been altered by the user? When we display a screen to the user with data from the DB, we want to know if they have altered any data so if they close the screen without saving we can prompt them to save. My first though was to wire up each control's "value changed" event and set a custom property to show that the record had been altered. That's not bad except I've got an average of 30 controls per form and am dealing with around 20 forms. There's got to be an easier way. Is there some kind of form-wide "value change" event that I can catch?
-
I've tried searching to see if this question has been asked before, but the search is not working for some reason. Does anybody know of an easy way to detect if a displayed record has been altered by the user? When we display a screen to the user with data from the DB, we want to know if they have altered any data so if they close the screen without saving we can prompt them to save. My first though was to wire up each control's "value changed" event and set a custom property to show that the record had been altered. That's not bad except I've got an average of 30 controls per form and am dealing with around 20 forms. There's got to be an easier way. Is there some kind of form-wide "value change" event that I can catch?
FyreWyrm wrote:
There's got to be an easier way.
There is.
FyreWyrm wrote:
Is there some kind of form-wide "value change" event that I can catch?
No. But if you used DataBinding then the Data Source you are bound to would actually keep track and you can use a method/property of the DataSource to find out if it has been modified.
FyreWyrm wrote:
I've got an average of 30 controls per form and am dealing with around 20 forms.
Is there some reason you are not using controls like tree/list/grid/PropertyGrid? These can greatly reduce the number of forms and controls needed to allow users to modify data.
led mike
-
I've tried searching to see if this question has been asked before, but the search is not working for some reason. Does anybody know of an easy way to detect if a displayed record has been altered by the user? When we display a screen to the user with data from the DB, we want to know if they have altered any data so if they close the screen without saving we can prompt them to save. My first though was to wire up each control's "value changed" event and set a custom property to show that the record had been altered. That's not bad except I've got an average of 30 controls per form and am dealing with around 20 forms. There's got to be an easier way. Is there some kind of form-wide "value change" event that I can catch?
A code-saving technique that few developers seem to be aware of is that you can wire multiple events to a single event handler. You can make each control's
Changed
event call the same function. Visual Studio's designers don't make this very easy, but you can enter the same function name in the Events part of the Properties pane for each control.DoEvents: Generating unexpected recursion since 1991
-
FyreWyrm wrote:
There's got to be an easier way.
There is.
FyreWyrm wrote:
Is there some kind of form-wide "value change" event that I can catch?
No. But if you used DataBinding then the Data Source you are bound to would actually keep track and you can use a method/property of the DataSource to find out if it has been modified.
FyreWyrm wrote:
I've got an average of 30 controls per form and am dealing with around 20 forms.
Is there some reason you are not using controls like tree/list/grid/PropertyGrid? These can greatly reduce the number of forms and controls needed to allow users to modify data.
led mike
led mike wrote:
if you used DataBinding
I'm curious as to how this would work. I did a datagrid once that I bound to a table in a DataSet and kept track of modifications that way. That was thrown back into my face by the standards review committee at work. They said we don't do data binding on controls but specifically set their text based on fields contained in a "business" object. I haven't used data binding since. I'll do some looking on this and see what I can figure out. Thanks. The forms I'm dealing with are mainly contract detail forms. There are tons of fields in the contracts and each field has its own field in the record. When the detail is displayed, each field has to have its own control.
-
A code-saving technique that few developers seem to be aware of is that you can wire multiple events to a single event handler. You can make each control's
Changed
event call the same function. Visual Studio's designers don't make this very easy, but you can enter the same function name in the Events part of the Properties pane for each control.DoEvents: Generating unexpected recursion since 1991
I've played around with this approach some and it's driving me up the wall. Apparently, the TextChanged event fires for a control when you programmatically change the text also. So when the form loads and I clear all the fields, the event fires for each field there. Then when I display a record, the event fires for each field there. Is there any way to suspend the firing of events on a form (like the suspend layout functions) while I manipulate the fields in the code? That would prevent unnecessary firing of this event. Thanks for your help.
-
I've tried searching to see if this question has been asked before, but the search is not working for some reason. Does anybody know of an easy way to detect if a displayed record has been altered by the user? When we display a screen to the user with data from the DB, we want to know if they have altered any data so if they close the screen without saving we can prompt them to save. My first though was to wire up each control's "value changed" event and set a custom property to show that the record had been altered. That's not bad except I've got an average of 30 controls per form and am dealing with around 20 forms. There's got to be an easier way. Is there some kind of form-wide "value change" event that I can catch?
FyreWyrm - the approach we take is to have our business objects implement the INotifyPropertyChanged interface.
public class Customer : INotifyPropertyChanged
{
private int _id = 0;
private string _customerName = string.Empty;public event PropertyChangedEventHandler PropertyChanged = new delegate { };
private void PropertyChanged(string value)
{
PropertyChanged(this, new PropertyChangedEventArgs(value));
}public string CustomerName
{
get { return _customerName; }
set
{
if (value != _customerName)
{
_customerName = value;
PropertyChanged("CustomerName");
}
}
}
}Any change to CustomerName will result in a property changed notification being raised. If you take a look into databinding (Link[^]), then you should find you can gain a real headstart.
Deja View - the feeling that you've seen this post before.
-
I've played around with this approach some and it's driving me up the wall. Apparently, the TextChanged event fires for a control when you programmatically change the text also. So when the form loads and I clear all the fields, the event fires for each field there. Then when I display a record, the event fires for each field there. Is there any way to suspend the firing of events on a form (like the suspend layout functions) while I manipulate the fields in the code? That would prevent unnecessary firing of this event. Thanks for your help.
You could unbind all events and rebind them afterwards but that isn't very good. Just set a flag (private boolean member) before you fill all your controls. In the changed event just check if the flag is set and do nothing if it is. After you have updated all controls just reset the flag:
private bool _inFill;
public void Fill(SomeClass data)
{
try
{
_inFill = true;//fill your controls with new data
} finally
{
_inFill = false;
}
}private void AllControlsChangedEventHandler(object sender, EventArgs e)
{
if (_inFill)
return;
//set changed flag or whatever
} -
led mike wrote:
if you used DataBinding
I'm curious as to how this would work. I did a datagrid once that I bound to a table in a DataSet and kept track of modifications that way. That was thrown back into my face by the standards review committee at work. They said we don't do data binding on controls but specifically set their text based on fields contained in a "business" object. I haven't used data binding since. I'll do some looking on this and see what I can figure out. Thanks. The forms I'm dealing with are mainly contract detail forms. There are tons of fields in the contracts and each field has its own field in the record. When the detail is displayed, each field has to have its own control.
You can bind to a "business" object, and have the business object keep track of changes (by having a _old value). DataBinding has their pro and con Pro: You get to have the value changed in business object as soon as the value is changed. Con: Due to the pro, sometime you need to be very careful of the sequence of change, especially is the changes triggers calculation which trigger changes, etc Setting and Saving values manually Pro: Doesn't has the DataBinding con: Con: Quite a lot con. Data changes is not populated back to the BO, so you may have code that manually repopulate part of the data to do some processing, aka, data out of sync between UI and BO.
-
led mike wrote:
if you used DataBinding
I'm curious as to how this would work. I did a datagrid once that I bound to a table in a DataSet and kept track of modifications that way. That was thrown back into my face by the standards review committee at work. They said we don't do data binding on controls but specifically set their text based on fields contained in a "business" object. I haven't used data binding since. I'll do some looking on this and see what I can figure out. Thanks. The forms I'm dealing with are mainly contract detail forms. There are tons of fields in the contracts and each field has its own field in the record. When the detail is displayed, each field has to have its own control.
-
Well, think about what's on a contract. Just the first little section, purchaser's Last Name, First Name, Address 1, Address 2, City, State, Zip-Code, Home Phone, Work Phone, Cell Phone is 10 textbox controls. Plus, this is taking the place of a very old Access application and the end users are very adament about it looking exactly like what they currently have. X|
-
FyreWyrm - the approach we take is to have our business objects implement the INotifyPropertyChanged interface.
public class Customer : INotifyPropertyChanged
{
private int _id = 0;
private string _customerName = string.Empty;public event PropertyChangedEventHandler PropertyChanged = new delegate { };
private void PropertyChanged(string value)
{
PropertyChanged(this, new PropertyChangedEventArgs(value));
}public string CustomerName
{
get { return _customerName; }
set
{
if (value != _customerName)
{
_customerName = value;
PropertyChanged("CustomerName");
}
}
}
}Any change to CustomerName will result in a property changed notification being raised. If you take a look into databinding (Link[^]), then you should find you can gain a real headstart.
Deja View - the feeling that you've seen this post before.
-
No problem mate. It also makes leaping into WPF a lot easier. :-D
Deja View - the feeling that you've seen this post before.
-
Well, think about what's on a contract. Just the first little section, purchaser's Last Name, First Name, Address 1, Address 2, City, State, Zip-Code, Home Phone, Work Phone, Cell Phone is 10 textbox controls. Plus, this is taking the place of a very old Access application and the end users are very adament about it looking exactly like what they currently have. X|
FyreWyrm wrote:
Just the first little section, purchaser's Last Name, First Name, Address 1, Address 2, City, State, Zip-Code, Home Phone, Work Phone, Cell Phone is 10 textbox controls.
Or 1 PropertyGrid control. ;) You can edit almost any data using a single PropertyGrid control. Furthermore you can use things like trees etc., to navigate the hierarchy of your data and at each navigation point you can edit that subset of the data in the same PropertyGrid control. Do you use Visual Studio? Did you not notice how the same control provides editing for all the data in your project?
led mike
-
FyreWyrm wrote:
Just the first little section, purchaser's Last Name, First Name, Address 1, Address 2, City, State, Zip-Code, Home Phone, Work Phone, Cell Phone is 10 textbox controls.
Or 1 PropertyGrid control. ;) You can edit almost any data using a single PropertyGrid control. Furthermore you can use things like trees etc., to navigate the hierarchy of your data and at each navigation point you can edit that subset of the data in the same PropertyGrid control. Do you use Visual Studio? Did you not notice how the same control provides editing for all the data in your project?
led mike
Sorry, I don't know anything about
PropertyGrid
s. This is the first Windows app ever developed by my company (and it's for internal use only). Furthermore, this is the first coding project I've been involved with. Up until now my career as a "programmer" (programmer in title only) has been limited to writing documentation for old web apps. But I'm enjoying my freedom with this one. I'm learning a lot. -
No problem mate. It also makes leaping into WPF a lot easier. :-D
Deja View - the feeling that you've seen this post before.
Pete, this is sort of working and sort of isn't. Tracking the changes is working, but something strange is happening with my objects. This form has a collection of records and only displays one record at a time allowing users to navigate through records. Any time fields are changed on the displayed record, the changes are translated automatically back up into the collection. Here's an example:
class Form
{
private Objects _objects = new Objects();
private Object _object = new Object();
private int _index = 0;private void Form\_Load(blah) { \_objects = GetAllObjects(); \_object = \_objects\[\_index\]; formBindingSource.DataSource = \_object; } private void NextButton\_Click(blah) { \_index++; \_object = \_objects\[\_index\]; formBindingSource.DataSource = \_object; }
}
When the user then changes any field on the screen, I see the setter called for that property (which is good). Then in the event handler for the "Next Record" button I can look at the collection, and all of their changes to the current object have been written back into the collection. I don't even have any code to set the object back into the collection! It's like when the databinding link is made my
_object
becomes a pointer to_objects[0]
instead of a copy of_objects[0]
. Any ideas? -
Pete, this is sort of working and sort of isn't. Tracking the changes is working, but something strange is happening with my objects. This form has a collection of records and only displays one record at a time allowing users to navigate through records. Any time fields are changed on the displayed record, the changes are translated automatically back up into the collection. Here's an example:
class Form
{
private Objects _objects = new Objects();
private Object _object = new Object();
private int _index = 0;private void Form\_Load(blah) { \_objects = GetAllObjects(); \_object = \_objects\[\_index\]; formBindingSource.DataSource = \_object; } private void NextButton\_Click(blah) { \_index++; \_object = \_objects\[\_index\]; formBindingSource.DataSource = \_object; }
}
When the user then changes any field on the screen, I see the setter called for that property (which is good). Then in the event handler for the "Next Record" button I can look at the collection, and all of their changes to the current object have been written back into the collection. I don't even have any code to set the object back into the collection! It's like when the databinding link is made my
_object
becomes a pointer to_objects[0]
instead of a copy of_objects[0]
. Any ideas?I'd have to see the classes to tell. Could you split your code out into a test project and then send it to me to have a look at? Email me from the link on this message and I'll send a reply so you know where to send the code to.
Deja View - the feeling that you've seen this post before.