I have an app that has been in production for awhile and yesterday I started getting emails about my app crashing. App built with latest Elements and DA. I did some debugging and i discovered this morning that now i seem to be caught in an loop in a PropertyChangedEvent. That event gets triggered from one field change, and in that event i update a second field, which then causes the event to get called again, and again, and again…
Is there a “proper” way to use this event in this manner without having your code go into a loop of death like this? As i said…this has worked up until now without any changes in this part of the code, so on a different level i’m a bit confused as to why this is an issue now.
Could you create a testcase for this issue? It is hard to say what is going wrong without actual code. You can drop the code to support@ so it will be kept private.
Set property A -> Raise event for property A ->
Set property B in the event handler -> Raise event for property B
-> Set property A in the event handler -> ...
then you have a circular dependency between properties and this code will (and should) crash.
Instead of relying on PropertyChaneEvent you could update property underlying fields in property setter and then raise PropertyChanged event for all changed properties.
How do i override the individual field setters? Do i need to move those declarations to the public section of the generated DA classes? I can’t edit the DA tabledefinitions classes since those are autogenerated by DA. What is the best approach to intercept the setters for individual fields?
So a class in question is a DA-generated Table Definition class?
As I understand you have 2 fields in a table that depend on each other and you need to keep them in sync.
There are several approaches for this (like defining separate calculated property or a method, or even modifying the generated source code).
Still you need to check a thing first
Please check your calculation logic. If there are 2 properties that depend on each other via some calculations then there should be no infinite event raisin loop. Take a look at this generated property setter:
method Employees.set__HomePhone(___value___: System.String);
begin
if System.Collections.Generic.Comparer<System.String>.Default.Compare(self.f____HomePhone, ___value___) ≠ 0 then begin
self.OnPropertyChanging('HomePhone');
self.f____HomePhone := ___value___;
self.OnPropertyChanged('HomePhone');
end;
end;
PropertyChanged event in not raised at all if you try to set a property to a value matching its current value. So there should be no dead events loop.
For WPF data binding purposes it might be easier to define a separate composite property. F.e. let’s assume that we have a Table Defintion class defined as
Note that this class is defined as partial.
To add a property you need to add a separate code file (that won’t be changed if you regenerate the table definition classes) and put there this code:
type
Employees = public partial class
private
method get_FullName(): String;
begin
exit self.FirstName + " " + self.LastName;
end;
method set_FullName(value: String);
begin
// Somehow split value to first name and last name parts
// Skipping this logic here
var fn := '....';
var ln := '....';
self.f____FirstName := fn;
self.f____LastName := ln;
self.OnPropertyChanged('FullName');
self.OnPropertyChanged('FirstName');
self.OnPropertyChanged('LastName');
end;
public
[RemObjects.DataAbstract.Linq.IgnoreProperty]
property FullName: String read get_FullName write set_FullName;
end;
This composite property now can be used for data binding etc. Note that changing this property also raises property notification events for related properties as well.