Data Binding to an Object that may be Read Only
-
If implementing INotifyPropertyChanged allows you to tell BindingSource when an object's properties have changed (and therefore the form needs to be updated) - how would you inform the BindingSource that a particular record/object is currently read-only (or not)? I was hoping for another interface to implement, but at this point I'm open to any ideas. The read-only state comes from another user write-locking the record.
-
If implementing INotifyPropertyChanged allows you to tell BindingSource when an object's properties have changed (and therefore the form needs to be updated) - how would you inform the BindingSource that a particular record/object is currently read-only (or not)? I was hoping for another interface to implement, but at this point I'm open to any ideas. The read-only state comes from another user write-locking the record.
The framework isn't expecting properties to change from "readonly" to something different. It's either compiled with only a getter, or it's writeable. You could throw a NotSupportedException prior to setting the value if it's readonly at the moment (and thus cancel setting it at all), but it would not be an ideal solution. Perhaps a better idea would be to split them, into say, a readonly CurrentFooBarState and a writeonly FooBarSetter.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
-
The framework isn't expecting properties to change from "readonly" to something different. It's either compiled with only a getter, or it's writeable. You could throw a NotSupportedException prior to setting the value if it's readonly at the moment (and thus cancel setting it at all), but it would not be an ideal solution. Perhaps a better idea would be to split them, into say, a readonly CurrentFooBarState and a writeonly FooBarSetter.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
It seems to be a big gap in the visual studio data-binding extensions - there is no support for read only entities or even read only properties. Properties that are compiled as read-only do not get treated any differently. I even implemented the ICustomTypeDescriptor interface, but the binding source, while it reads off a set of properties for each object, it only checks the "IsReadOnly" property from the first record, and it doesn't even appear to affect how it binds the data source to the controls. I am coping with the issue by: 1) each entity implements IEditableObject. 2) in the IEditableObject.BeginEdit() method, the entity attempts to acquire a lock. If it cannot acquire the lock, the entity is ReadOnly. I removed any exceptions thrown at this point: the lock fails silently. 3) I have handled the CurrentItemChanged event from the BindingSource. In this handler, I check if the entity is read-only, and update the enabled state of the associated controls. This seems to be working for now, but I am faced with another issue: the BindingSource component, doesn't always call IEditableObject.EndEdit() or IEditableObject.CancelEdit() for every item it has called IEditableObject.BeginEdit() on.... this seems like a fairly dramatic design flaw in this component. Am I not disposing of it correctly?
-
It seems to be a big gap in the visual studio data-binding extensions - there is no support for read only entities or even read only properties. Properties that are compiled as read-only do not get treated any differently. I even implemented the ICustomTypeDescriptor interface, but the binding source, while it reads off a set of properties for each object, it only checks the "IsReadOnly" property from the first record, and it doesn't even appear to affect how it binds the data source to the controls. I am coping with the issue by: 1) each entity implements IEditableObject. 2) in the IEditableObject.BeginEdit() method, the entity attempts to acquire a lock. If it cannot acquire the lock, the entity is ReadOnly. I removed any exceptions thrown at this point: the lock fails silently. 3) I have handled the CurrentItemChanged event from the BindingSource. In this handler, I check if the entity is read-only, and update the enabled state of the associated controls. This seems to be working for now, but I am faced with another issue: the BindingSource component, doesn't always call IEditableObject.EndEdit() or IEditableObject.CancelEdit() for every item it has called IEditableObject.BeginEdit() on.... this seems like a fairly dramatic design flaw in this component. Am I not disposing of it correctly?
Simon Bridge wrote:
Am I not disposing of it correctly?
Let's find out; does the thing implement IDisposable? Add it if not, override if it does, and use the method to write a message to the VS-output.
Simon Bridge wrote:
the BindingSource component, doesn't always call IEditableObject.EndEdit() or IEditableObject.CancelEdit() for every item it has called IEditableObject.BeginEdit() on.... this seems like a fairly dramatic design flaw in this component.
Soo, it still had focus when being removed from the form? The user didn't cancel his edit-mode, move focus to end editing? What happens if you manually focus something else, like a dead button, before removing it from the form?
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
-
Simon Bridge wrote:
Am I not disposing of it correctly?
Let's find out; does the thing implement IDisposable? Add it if not, override if it does, and use the method to write a message to the VS-output.
Simon Bridge wrote:
the BindingSource component, doesn't always call IEditableObject.EndEdit() or IEditableObject.CancelEdit() for every item it has called IEditableObject.BeginEdit() on.... this seems like a fairly dramatic design flaw in this component.
Soo, it still had focus when being removed from the form? The user didn't cancel his edit-mode, move focus to end editing? What happens if you manually focus something else, like a dead button, before removing it from the form?
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
BindingSource
is anIComponent
, the main definition of a component being that it implementsIDisposable
, - so yes it does have aDispose
method, and this is being correctly invoked by the 'Container
' on the form when it gets disposed. However, I think I have discovered the problem. The issue is the record that is currently on-screen (so it's a data-input form with text-boxes, combo's etc. - not a data-grid) When you close the form, the record currently on screen, (which was put into edit mode as soon as the record became current) is not removed from edit-mode. Turns out, there areCancelEdit()
andEndEdit()
methods on theBindingSource
object itself. I trapped theForm.Closing
event, and invokedCancelEdit()
on the primary binding source for the form, and it now releases all the locks. I put in some logic to determine if the current record has pending changes, and callEndEdit()
instead to keep the changes. This even works when the binding source has other data sources hanging off it (i.e. when a property of the current object/record is itself a data-source ('cos its a list), - on some forms in my system this can cause upward of 50 records being locked at one time, which was causing lots of headaches when they weren't unlocking) I am still a little unsure why you have to explicitly call eitherEndEdit()
orCancelEdit()
from the binding source - I would have put clean-up code in theDispose
method if I were writing the class. My best guess is that the Begin-End/Cancel edit semantics are more closely coupled with theDataRow
andDataGridView
components. -
BindingSource
is anIComponent
, the main definition of a component being that it implementsIDisposable
, - so yes it does have aDispose
method, and this is being correctly invoked by the 'Container
' on the form when it gets disposed. However, I think I have discovered the problem. The issue is the record that is currently on-screen (so it's a data-input form with text-boxes, combo's etc. - not a data-grid) When you close the form, the record currently on screen, (which was put into edit mode as soon as the record became current) is not removed from edit-mode. Turns out, there areCancelEdit()
andEndEdit()
methods on theBindingSource
object itself. I trapped theForm.Closing
event, and invokedCancelEdit()
on the primary binding source for the form, and it now releases all the locks. I put in some logic to determine if the current record has pending changes, and callEndEdit()
instead to keep the changes. This even works when the binding source has other data sources hanging off it (i.e. when a property of the current object/record is itself a data-source ('cos its a list), - on some forms in my system this can cause upward of 50 records being locked at one time, which was causing lots of headaches when they weren't unlocking) I am still a little unsure why you have to explicitly call eitherEndEdit()
orCancelEdit()
from the binding source - I would have put clean-up code in theDispose
method if I were writing the class. My best guess is that the Begin-End/Cancel edit semantics are more closely coupled with theDataRow
andDataGridView
components.Simon Bridge wrote:
Turns out, there are
CancelEdit()
andEndEdit()
methods on theBindingSource
object itself.Not exactly where one would expect them, but such things happen..
Simon Bridge wrote:
this can cause upward of 50 records being locked at one time
..with bigger implications than expected.
Simon Bridge wrote:
My best guess is that the Begin-End/Cancel edit semantics are more closely coupled with the
DataRow
andDataGridView
components.Every "Forms"-controls is in edit-mode as long as it has the input-focus. It would sound more logical that "editing" would end as soon as the control is disposed of.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]