Custom property flow reading error

594 views Asked by At

I'm a french user of Delphi 2010 so please excuse my bad english.

I've created a control from a TCustomControl. This control have a TOwnedCollection populated by TCollectionItem descendant. Those Items have a published custom list property. This list is a list of couples of integers made by me. I've written a custom designtime editor for this property and it works perfectly. So now, I want to write the list data into the dfm and it becomes a bit harder.

Here is what I've done:

TPedroGraphLineCollectionIem = class(TCollectionItem)
  published
    property PointList: TPedroIntegerCoupleList read FList write SetList
      stored GetStored;

...
procedure TPedroGraphLineCollectionIem.DefineProperties(Filer: TFiler);
begin
  inherited;
  //'PointList' : the property name
  //FList.Count > 0 : Is the list empty ?
  Filer.DefineProperty('PointList', ReadListData, WriteListData,
    (FList.Count > 0));
end;
...
procedure TPedroGraphLineCollectionIem.ReadListData(Reader: TReader);
var
  Val1, Val2: Integer;
begin
  with Reader do
  begin
    ReadListBegin;
    while not EndOfList do
    begin
      Val1 := ReadInteger;
      Val2 := ReadInteger;
      FList.AddCouple(Val1, Val2);
    end;
    ReadListEnd;
  end;
end;
...
procedure TPedroGraphLineCollectionIem.WriteListData(Writer: TWriter);
var
  I: Integer;
begin
  with Writer do
  begin
    WriteListBegin;
    for I := 0 to Count - 1 do
    begin
      WriteInteger(FList[I].Value1);
      WriteInteger(FList[I].Value2);
    end;
    WriteListEnd;
  end;
end;

The WriteListData procedure works perfectly and writes the values into the dfm. But when I try to load the Form, it always crashes and a dialog box tell me that there is an reading flow error on this property.

FList is created inside the constructor of the class.

Here is the .dfm :

object MainFrm: TMainFrm
  Left = 0
  Top = 0
  Caption = 'MainFrm'
  ClientHeight = 425
  ClientWidth = 689
  Color = clBtnFace
  ParentFont = True
  OldCreateOrder = False
  Position = poScreenCenter
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object PedroGraph1: TPedroGraph
    Left = 120
    Top = 136
    Width = 313
    Height = 209
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
    Lines = <
      item
        LinePen.Color = clRed
        PointList = (
          1
          2
          3
          4)
      end>
    MarksFont.Charset = DEFAULT_CHARSET
    MarksFont.Color = clWindowText
    MarksFont.Height = -11
    MarksFont.Name = 'Tahoma'
    MarksFont.Style = []
  end
end

Error Messages (in french) :

1

Erreur lors de la lecture de TPedroGraphLineCollectionItem.PointList: Valeur de propriété incorrecte. Ignorer l'erreur et continuer ?Remarque: ceci peut provoquer la suppression de composants ou la perte de valeurs de propriété

2

Erreur lors de la lecture de TPedroGraphLineCollectionItem.□□: la propriété □□ n'existe pas. Ignorer l'erreur et continuer ?Remarque: ceci peut provoquer la suppression de composants ou la perte de valeurs de propriété

Note: the '□' char is really displayed as this.

3

Erreur lors de la lecture de TPedroGraphLineCollectionItem.□□

4

Erreur lors de la lecture de PedroGraphLines1.Lines: Valeur de propriété incorrecte. Ignorer l'erreur et continuer ?Remarque: ceci peut provoquer la suppression de composants ou la perte de valeurs de propriété

5

Erreur à la création de la fiche : Erreur de lecture du flux.

Declaration of TPedroIntegerCoupleList:

TPedroIntegerCouple = record
  Value1: Integer;
  Value2: Integer;
end;

TPedroGenericList<T> = class(TList<T>)
private
  FOnChange: TNotifyEvent;
  FUpdating: Boolean;
protected
  procedure Notify(const Item: T; Action: TCollectionNotification); override;
  procedure DoChange;
published
public
  constructor Create;
  procedure SortCustom; virtual; abstract;
  procedure Assign(const Source: TPedroGenericList<T>);
  property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;

TPedroIntegerCoupleList = class(TPedroGenericList<TPedroIntegerCouple>)
private
  function GetString: String;
  procedure SetString(const Value: String);
public
  procedure SortCustom; override;
  function AddCouple(const Value1, Value2: Integer): Integer;
  procedure InsertCouple(const Index, Value1, Value2: Integer);
  property AsString: String read GetString write SetString;
end;

Where am I wrong ?

1

There are 1 answers

17
Arioch 'The On BEST ANSWER

I think you miss the point of DefineProperty and published They are mutually exclusive.

  • published means the VCL would store the real property by it's own means.
  • DefineProperty means there is no such real property but you would pretend like if there were some virtual one.

what is your DFM ? May it be that 'PointList' is stored twice there - as the list and as the component ?

If so - you should select only one method of saving it ether one way or another, for example making the property PUBLIC rather than PUBLISHED.

Or maybe you may try to make non-clashing names like

property PointList: TPedroIntegerCoupleList read FList write SetList stored FALSE;

Filer.DefineProperty('PointList_Virtual_DATA', ....