- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
IsDirty property bound to button (enabled)
Joined: 25-Mar-2008
Hello,
We are currently evaluating llblgen Pro. We are using .NET DataBinding and build in Validation with errorproviders.
In our application, we have multiple "entity editing" forms. These forms are typically used to edit a single instance of an Entity. These forms contain Save/Cancel/Apply buttons. We bound the Enabled properties of the Save and Apply to the IsDirty property of the entity class, for example:
btnSave.DataBindings.Add("Enabled", location, "IsDirty");
When the form is displayed, the buttons are disabled, and when the user modifies data, the buttons are enabled. So far, so good. However, if we click the Apply button, the buttons are not disabled (while the IsDirty property is set to false).
We added a "utility function" to correct this behaviour:
/// <summary>
/// Update the control's IsDirty DataBinding
/// </summary>
/// <param name="controls">The controls to force updates for</param>
public static void UpdateIsDirtyDataBindings(params Control[] controls)
{
foreach (Control c in controls)
{
if ((c != null) && (c.DataBindings["Enabled"] != null))
{
c.DataBindings["Enabled"].ReadValue();
}
}
}
While this function does the job, we are wondering if there is a better way to automate this behaviour (are we forgetting something?). It appears the PropertyChanged method is not called (for IsDirty) when saving or refetching an Entity class.
We tried updating the CommonEntityBase class, to force a PropertyChanged event if the save operation was succesfull (by overriding the save function). The problem occurred with refetch, which is abstract at this level.
We would like to skip the manual update step, since this behaviour is on every Form and Custom Control throughout our application (not all forms are closed after clicking save). Adding it manually everywhere will cause errors (maintenance has a high priority in our project). Any comments/suggestions are welcome.
Kind regards,
Jeroen.
Edit: We are using the latest demo version (2.5 Final Demo) with .NET 3.5, template: (SelfServicing.TwoClasses 2008 )
The EntityBase class exposes an event called **AfterSave **which accoriding to the reference manual is fired each time this entity is persisted. Related entities can subscribe to this event to start housekeeping actions, like syncing internal FK fields with the PK fields of this entity
Would this help you?
ref: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=12180
Joined: 25-Mar-2008
I think you misunderstood our problem.
Our application works with DataBinding. I'll go into the details this time:
For example: Suppose we have a simple edit Form, with the following controls: - txtName (TextBox), - txtDescription (TextBox) - btnSave (Button) - btnReload (Button) - errors (ErrorProvider)
This Form also has a LocationEntity as a property. The LocationEntity has the properties: - LocationId (PK), - Name, - Description
The Form has a private field:
private LocationEntity location;
We have a utility class, with the following helper function (this will be used later on):
/// <summary>
/// binds a control to a property, and sets the update mode to OnPropertyChanged
/// </summary>
/// <param name="c">The name of the control property to bind</param>
/// <param name="propertyName">The property of the control</param>
/// <param name="dataSource">An <see cref="object"/> that represents the datasource</param>
/// <param name="dataMember">The property or list to bind to</param>
public static void BindControl(Control c, string propertyName, object dataSource, string dataMember)
{
Binding b;
b = c.DataBindings[propertyName];
if (b != null)
{
c.DataBindings.Remove(b);
}
b = c.DataBindings.Add(propertyName, dataSource, dataMember);
b.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
}
When this LocationEntity property of the Form is set to an LocationEntity instance, the Form binds it's controls to the LocationEntity's properties (using the following function):
private void bindMembers()
{
Utilities.BindControl(txtName, "Text", location, LocationFieldIndex.Name.ToString());
Utilities.BindControl(txtDescription, "Text", location, LocationFieldIndex.Description.ToString());
// ------- Buttons -------
Utilities.BindControl(btnReload, "Enabled", location, "IsDirty");
Utilities.BindControl(btnSave, "Enabled", location, "IsDirty");
errors.DataSource = location;
}
When you pass a LocationEntity to this Form, it will bind it's controls to it. The Save and Reload buttons are disabled untill you change something. Validation works as expected (while you type). This is all very neat (and simple).
Now for our problem: We have the following event handlers on the Save and Reload button:
private void btnReload_Click(object sender, EventArgs e)
{
location.Refetch();
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
location.ValidateEntity();
location.Save();
}
catch (ORMException)
{
errors.UpdateBinding();
}
}
Now the following (common scenario): (1) The Form is opened with the following location: Name: Test Location Description: A test Location! [The Save and Reload buttons are disabled]
(2) The user changes the name to "Real Location" [The Save and Reload buttons become enabled]
(3) The user empties the Description
(4) The user clicks reload [Reload calls Refetch() on the Form's LocationEntity]
(4: Alternative) The user clicks Save [Save calls Save() on the Form's LocationEntity]
Now, the expected result would be that the Form is displaying the refetched (previous) values (only if we clicked Reload). In both cases, the Save and Reload buttons should be disabled (they are bound to IsDirty). The reality is that the buttons are still enabled, and the data displayed is the modified data. The properties on the datasource, however, did change to their original value, and IsDirty became false.
We traced the problem down to the following: EntityClasses do not call PropertyChanged when they are Refetched or Saved, so the bound UI components are never notified of the changes made.
We added the following function to the CommonEntityBase class:
/// <summary>
/// Sends PropertyChanged events for all specified fields
/// </summary>
/// <typeparam name="T">The EntityFieldIndex to use</typeparam>
public void Refresh<T> ()
{
string[] names = null;
try
{
names = Enum.GetNames(typeof(T));
}
catch (Exception)
{
return;
}
foreach (string name in names)
{
try
{
OnPropertyChanged(name);
}
catch (Exception)
{
}
}
OnPropertyChanged("IsDirty");
}
Now, on the Save and Reload buttons, we added the following line of code:
location.Refresh<LocationFieldIndex>();
This does the job (all UI controls work as expected). The downside is the manditory manual call to Refresh<T>(). We where wondering if there is a build-in way to handle this databinding behaviour manually, or if there is a better alternative.
I think the question became a feature request but I hope our explaination helps you understand what we would like to achieve and maybe help other people out with their DataBinding (on a single entity).
Joined: 25-Mar-2008