Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 04/03/23 in all areas

  1. That was very helpful, better than the awesome documentation floating about; Things I learnt. The CustomFormat property on a TPrototypeBindSource field is not used when binding to a StringGrid, If you are binding to bothat a Grid and control, set the CustomFormat on the grid as well. I wrote a couple of procedure to populate the BindSource fields and the Grid columns. A bit of inspiration/plagiarism for the binding method 🙂 I hope someone may find it useful. Cheers ps: the const I used for replacing the Date with a "blank" currently say '<Blank>' just for proof of concept/testing purposes. Please change it/anything else as required. And If I have any brain farts in the code. Please let me know 🙂 unit my.System.BindUtil; interface uses System.Classes , System.SysUtils , System.Bindings.Methods , System.Bindings.EvalProtocol , System.Bindings.Consts , Data.Bind.Components , Data.Bind.Grid , Data.Bind.ObjectScope ; { https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Creating_Custom_LiveBindings_Methods } const _sID_BindMethod_BlankDateToString = 'BlankDateToString'; _sBlankDate = '<BLANK>'; _BlankInputDate = 0; _FormatBlankDateToString = _sID_BindMethod_BlankDateToString +'(%s)'; Type TBindingUtil = Class /// Class Procs for setting CustomFormats for TDate properties /// /// useful for the TProtoTypeBindSource and the TAdapterBindSource /// /// Use this to Map a Class to a Collection of FieldDef. It populates the /// BindSource fields and sets the CustomFormat for and TDate Fields /// /// TBindingUtil.MapFieldDefs(fListBindSource.FieldDefs, fImportClass); /// /// /// Once the Gridlink is established if you dont want to hand populate it /// and want to see all the fields, then call this. It populates the grid /// columns and sets the CustomFormat for and TDate Fields /// /// TBindingUtil.CreateGridColumns(FGridLink, 150); /// class Procedure MapFieldDefs (FieldDefs: TGeneratorFieldDefs; AClass:TClass); class Procedure CreateGridColumns (Link : TLinkGridToDataSource; DefWidth: Integer = 0); End; TBindMethods = Class class function MethodBlankDateToString: IInvokable; end; implementation uses REST.Response.Adapter , System.TypInfo , System.Rtti , Data.DB , Data.Bind.DBScope ; { TBindingUtil } class procedure TBindingUtil.CreateGridColumns(Link: TLinkGridToDataSource; DefWidth: Integer); var DS: TBaseLinkingBindSource; GenFieldDefs: TGeneratorFieldDefs; FieldDefs: TFieldDefs; P: TPrototypeBindSource; GFld: TGeneratorFieldDef; DBFldDef: Data.DB.TFieldDef; Clm: TLinkGridToDataSourceColumn; I: Integer; begin DS := Link.DataSource; FieldDefs := Nil; GenFieldDefs := Nil; If DS Is TPrototypeBindSource Then Begin GenFieldDefs := TPrototypeBindSource(DS).FieldDefs; End; /// /// If DS Is TAdapterBindSource Then begin if Assigned(TAdapterBindSource(DS).Adapter) then begin if TAdapterBindSource(DS).Adapter is TDataGeneratorAdapter then GenFieldDefs := TDataGeneratorAdapter(TAdapterBindSource(DS).Adapter).FieldDefs; end; end; If DS Is TBindSourceDB Then begin if Assigned(TBindSourceDB(DS).DataSet) then FieldDefs := TBindSourceDB(DS).DataSet.FieldDefs; end; /// Make sure we have a valid collection before we go forward /// if GenFieldDefs <> Nil then Begin Link.Columns.Clear; For GFld In GenFieldDefs Do Begin Clm := Link.Columns.Add; Clm.Header := GFld.Name; Clm.MemberName := GFld.Name; If DefWidth <> 0 Then Clm.Width := DefWidth Else Clm.Width := Link.DefaultColumnWidth; If (GFld.FieldType = TGeneratorFieldType.ftDate) Or ((GFld.FieldType = TGeneratorFieldType.ftDateTime)) Then Clm.CustomFormat := _FormatBlankDateToString End; End else if FieldDefs <> Nil then Begin Link.Columns.Clear; /// For DFld In FieldDefs Do /// /// Didnt work, for some reason FieldDef -> namedItem -> CollectionItem /// /// Cannot be seen as a CollectionItem ????? /// for I := 0 to FieldDefs.Count-1 do Begin DBFldDef := FieldDefs[I]; Clm := Link.Columns.Add; Clm.Header := DBFldDef.Name; Clm.MemberName := DBFldDef.Name; If DefWidth <> 0 Then Clm.Width := DefWidth Else Clm.Width := Link.DefaultColumnWidth; If (DBFldDef.DataType = TFieldType.ftDate) Or ((DBFldDef.DataType = TFieldType.ftDateTime)) Then Clm.CustomFormat := _FormatBlankDateToString End; End; End; class procedure TBindingUtil.MapFieldDefs(FieldDefs: TGeneratorFieldDefs; AClass: TClass); var Ctx: TRttiContext; Typ: TRttiType; Prps: TArray<TRttiProperty>; I: Integer; Prp: TRttiProperty; PrpTypInfo: PTypeInfo; F:TGeneratorFieldDef; X: Integer; begin if FieldDefs.Count = 0 then begin Ctx := TRttiContext.Create; Typ := Ctx.GetType(AClass); Prps := Typ.GetProperties; /// loop through the properties to add the fieldds to the /// fielddef collection. /// For I := 0 To Length(Prps) - 1 Do Begin Prp := Prps[I]; PrpTypInfo := Prp.PropertyType.Handle; /// if the Field does not exist, Add it and then fill in the name and /// read only property /// /// Dont use FieldDefs.Find(Prp.Name) as it throws a exception if it doesnt /// find anything, also it uses IndexOf anyway /// X := FieldDefs.IndexOf(Prp.Name); if X<0 then F := Nil else F := FieldDefs[I]; if not Assigned(F) then begin F := FieldDefs.AddFieldDef; F.Name := Prp.Name;; F.ReadOnly := not Prp.IsWritable; end; /// make sure the FieldType is set, if its a Date then set the custom format /// Case PrpTypInfo.Kind Of tkEnumeration, tkInteger, tkInt64: F.FieldType := TGeneratorFieldType.ftInteger; tkFloat: Begin F.FieldType := TGeneratorFieldType.ftSingle; If PrpTypInfo = System.TypeInfo(TDate) Then Begin F.FieldType := TGeneratorFieldType.ftDate; F.CustomFormat := _FormatBlankDateToString; End; If PrpTypInfo = System.TypeInfo(TTime) Then Begin F.FieldType := TGeneratorFieldType.ftTime; F.CustomFormat := _FormatBlankDateToString; End; If PrpTypInfo = System.TypeInfo(TDateTime) Then Begin F.FieldType := TGeneratorFieldType.ftDateTime; F.CustomFormat := _FormatBlankDateToString; End; End; tkVariant, tkChar, tkWChar, tkString, tkLString, tkWString, tkUString: F.FieldType := TGeneratorFieldType.ftString; End; End; End; End; { TBindMethods } class function TBindMethods.MethodBlankDateToString: IInvokable; begin Result := MakeInvokable( function(Args: TArray<IValue>): IValue var InputValue: IValue; OutputString: String; begin // Ensure only one argument is received. if Length(Args) <> 1 then raise EEvaluatorError.Create(sFormatArgError); // Ensure that the received argument is a Float and of Type Date/DateTime. InputValue := Args[0]; If InputValue.GetType.Kind = tkFloat Then Begin If (InputValue.GetType = System.TypeInfo(TDate)) Or (InputValue.GetType = System.TypeInfo(TDateTime)) Then Begin /// if the value is 0 then its blank and assign the output to be the blank string /// from the consts /// If InputValue.GetValue.AsExtended = 0 Then OutputString := _sBlankDate Else OutputString := DateToStr(InputValue.GetValue.AsExtended) End Else OutputString := InputValue.GetValue.ToString; End Else OutputString := InputValue.GetValue.ToString; // Return the output string. Result := TValueWrapper.Create(OutputString); End); end; initialization if not TBindingMethodsFactory.HasMethod(_sID_BindMethod_BlankDateToString) then TBindingMethodsFactory.RegisterMethod( { AMethodDescription : TMethodDescription } TMethodDescription.Create( { } TBindMethods.MethodBlankDateToString, { AInvokable : IInvokable } _sID_BindMethod_BlankDateToString, { AID : string } _sID_BindMethod_BlankDateToString, { Name : string } 'my.System.BindUtil', { AUnitName : string } true, { ADefaultEnabled : boolean } sFormatDesc, { ADescription : string } nil { AFrameWorkClass : TPersistentClass } ) { } ); finalization TBindingMethodsFactory.UnRegisterMethod(_sID_BindMethod_BlankDateToString); end.
  2. CoeurdeLeon

    Anyone know why?

    The position in Frederick, Maryland is about 20 miles from my house. For the last 4 years this company has been advertising remote Delphi Developer positions working for the Legal & General America Headquarters located at 3275 Bennett Creek Ave in Frederick, MD 21704, United States. Many days I would receive 6 calls a day from different headhunters looking to fill this position. Frequently the connection is very bad (voip) and the indian accent is very difficult to understand. I have interviewed with one of the vendors trying to fill the position, Diverse Lynx. Eventually, I cut off all communications with this company because they appeared to be human traffickers and completely untrustworthy. I am a grey beard as was mentioned in one of the earlier posts. I could do the job with very little effort. Something is very fishy about this position in Frederick, MD. They are looking to fill the position for $50/hour. Dick Maley
  3. LiveBinding allow that you create yourself "Methods / Conversors" to use in your projects: Create a new package (DPK) to create your procedure, for example: unit uMyMethodInvokable; interface // more info: RAD Studio HELP SYSTEM: Creating Custom LiveBindings Methods implementation uses System.SysUtils, System.Bindings.Methods, System.Bindings.EvalProtocol, System.Bindings.Consts, System.TypInfo, // System.Rtti, System.MaskUtils, System.DateUtils; // function named: MakeMethod"XXXXXXXXXXX" convention LiveBinding!!! function MyMakeMethodDateAsStringEmpty: IInvokable; begin // return a "anonimous-function "Invokable" type... result := MakeInvokable( { } function(Args: TArray<IValue>): IValue var InputValue: IValue; // receive the value in "%s" passed InputString, OutputString: string; begin // ensure only one argument is received... not more or less!!! => "%s" ---> not "%s, %s" etc... if (Length(Args) <> 1) then raise EEvaluatorError.Create(sFormatArgError); // // ensure that the received argument InputValue := Args[0]; // // if not(InputValue.GetType.Kind in [tkString, tkWideString, tkWChar, tkWString]) then // raise EEvaluatorError.Create('Error 2: ' + sFormatExpectedStr); // // my output will be a "string" with Date text!!! if InputValue.GetType.Kind = tkFloat then begin OutputString := InputValue.GetValue.ToString; // if (OutputString = '30/12/1899') then OutputString := ''; end else OutputString := '01/01/1981'; // // return the output as "IValue", expected by LiveBinding calls!!! result := TValueWrapper.Create(OutputString); end); end; initialization TBindingMethodsFactory.RegisterMethod( { AMethodDescription : TMethodDescription } TMethodDescription.Create( { } MyMakeMethodDateAsStringEmpty, { AInvokable : IInvokable } 'MyDateAsStringEmptyCustom', { AID : string } 'MyDateAsStringEmptyCustom', { Name : string } 'uMyMethodInvokable', { AUnitName : string } true, { ADefaultEnabled : boolean } sFormatDesc, { ADescription : string } nil { AFrameWorkClass : TPersistentClass } ) { } ); finalization TBindingMethodsFactory.UnRegisterMethod('MyDateAsStringEmptyCustom' { AID : string } ); end. Now, build and install the new package ... "MyDateAsStringEmptyCustom" methods is avaliable for use in any project using LiveBindings, now! now, just use it in your LiveBinding field, like this: Vcl.StdCtrls {} , uMyMethodInvokable {my custom method} ; type TForm1 = class(TForm) PrototypeBindSource1: TPrototypeBindSource; BtnEditRecord: TButton; BindingsList1: TBindingsList; StringGridPrototypeBindSource1: TStringGrid; LinkGridToDataSourcePrototypeBindSource1: TLinkGridToDataSource; NavigatorPrototypeBindSource1: TBindNavigator; Label1: TLabel; procedure BtnEditRecordClick(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.BtnEditRecordClick(Sender: TObject); var LDate: TArray<TDate>; i : integer; begin LDate := [ StrToDate('30/12/1899'), StrToDate('30/12/1900') ]; // i := random(2); Label1.Caption := 'Current value: ' + DateToStr(LDate[i]); // PrototypeBindSource1.DataGenerator.Edit; PrototypeBindSource1.DataGenerator.Fields.Items[0].SetTValue(LDate[i]); PrototypeBindSource1.DataGenerator.Fields.Items[1].SetTValue(LDate[i]); end; procedure TForm1.FormShow(Sender: TObject); begin StringGridPrototypeBindSource1.DefaultColWidth := 200; end;
×