Is it possible to programmatically change the methods for writing properties using RTTI to create object controls?

I have a business object that I would like to β€œconnect” to my interface. I saw some partial solutions for creating data objects, but they all made significant changes to my business object, including an additional level of abstraction.

I studied the improved RTTI in new versions of Delphi, and it looks very interesting and useful. I am wondering if I can use it to programmatically introduce new recording methods for all properties.

The way this will work is that my descendant TEdit could give a reference to the property of the object when creating the form. TEdit then inserts a reference to itself in the attribute for this property (and, of course, removes itself on the destructor or receives another link). TEdit also ensures that the recording method for the property is replaced with the one that notifies TEdit of the changes after calling the original recording method.

Is it possible? A big cork stopper will be that injecting a new recording method is not possible, so there is a heading for this question.

There are also potential problems with derived properties, but for this it should be possible to find a solution.

+4
source share
3 answers

In this post entitled To Call the Great Separation , Cobus Krueger talked about business objects.

The solution that he prepared basically meets your requirements:

  • Use the advanced RTTI features introduced in the latest version of Delphi.
  • Separation of business logic into presentation logic.

Any PODO object (a regular old Delphi object) will work as a business object!

The magic lies in the TObjectBinding class, which associates any TWinControl with any business object.

Excerpts:

TObjectBinding = class private fCtx: TRttiContext; fControlType: TRttiType; fObjType: TRttiType; fPropFieldMapping: TDictionary<TRttiProperty, TRttiField>; // Dictionary of object Properties & corresponding Fields fControl: TWinControl; // The control (normally form) fObj: TObject; // Object it represents. procedure CreateMappings; function FindField(Prop: TRttiProperty; out Field: TRttiField): Boolean; function FieldClass(Field: TRttiField): TClass; // Modify these to change the rules about what should be matched. function IsValidField(Field: TRttiField): Boolean; function IsValidProp(Prop: TRttiProperty): Boolean; // Modify these to change the mappings of property type to VCL control class. procedure AssignField(Prop: TRttiProperty; Field: TRttiField); procedure AssignProp(Prop: TRttiProperty; Field: TRttiField); // Used from AssignField/AssignProp. Extend these to support a wider range of properties. function GetPropText(Prop: TRttiProperty): string; procedure SetPropText(Prop: TRttiProperty; const Text: string); public constructor Create(Control: TWinControl; Obj: TObject); destructor Destroy; override; // procedure Load; procedure Save; end; 

I hope this will be a good starting point for you.

0
source

Your question has already put you ahead of me with programming skills, so I’ll just add how I could approach this:

If I tried to write something like this, I would probably start with a TList for each field in your TBusinessObject. This list will be used to indicate what needs to be updated when you need to push changes.

So, when TEdit is created, it will add itself to the list that was associated with the data part in your TBusinessObject. When TBusinessObject updated this piece of data, it will then go through the list of connected objects. He will see TEdit and, knowing that it is TEdit, will run the code for updating .Text. If I attach TCaption, then the code will update .Caption.

TEdit, as you indicated, will have to inform TBusinessObject when it is updated. I think this is a difficult place - you can create a new TEdit and add a TList to support who it should let you know when it changes. If you used .Tag to indicate the field number in TBusinessObject, then OnChange (or any other event) might trigger something like TBusinessObject.FieldUpdate [TEdit.Tag, NewValue], which then triggers your business logic. This, in turn, can cause TBusinessObject to update other fields, which may have their own TLists for updated fields.

Preventing circular updates will require that you have a way to update the control without triggering events. For the one program I wrote, I had two methods for updating the control: SetValue and ChangeValue. SetValue disabled any events (OnChange, OnValidate), updated the control value, and then re-enabled the events. ChangeValue simply changed the value and resolved any of the control events as required.

There are probably easier ways to do this, but hopefully this gives you food for thought.

+1
source

Is it possible to programmatically change the methods for writing properties using RTTI to create object-oriented controls?

No, It is Immpossible. RTTI provides you with information; it does not allow you to change types at runtime.

The big cork stopper will be that introducing a new recording method is not possible, so the title for this question

To change this at runtime, there must be something similar to an event handler that you can install. This is a lightweight concept, but it has some costs at runtime, both during a conversation (this would be an indirectness, where there would usually be a direct call), and in terms of the required memory (for each property, an additional TEvent style field will be required). This is easy to implement if you need it, but it would be harmful if the compiler automatically generated such code for all classes, just in case.

If you are considering somehow correcting the code in memory at run time, this will not work, and it will be, at best, unreliable.

+1
source

Source: https://habr.com/ru/post/1397817/


All Articles