Question: I am trying to implement a simple contact manager using the VirtualStringTree component. I have it set up to look like a list-view component with only three columns that will all contain text:

![Layout](https://i.stack.imgur.com/fBlWS.jpg)

For the data structure, I am using svTree by Linas, which was mentioned in another Stack Overflow question.

I have declared a record like this:

```
type
  TMainData = record
    Name, Email, Password: string;
  end;

```

In the form's OnCreate I have this:

```
procedure TForm1.FormCreate(Sender: TObject);
begin
  MyTree := TSVTree<TMainData>.Create(False);
  MyTree.VirtualTree := vst1;
end;

```

I am adding the data from TEdits like this:

```
procedure TForm1.BuildStructure;
var
  svNode: TSVTreeNode<TMainData>;
  Data: TMainData;
begin
  MyTree.BeginUpdate;
  try
    Data.Name := edtname.Text;
    Data.Email := edtEmail.Text;
    Data.Password := edtPassword.Text;
    svNode := MyTree.AddChild(nil, Data);
  finally
    MyTree.EndUpdate;
  end;
  Label1.Caption := 'Count: '+IntToStr(MyTree.TotalCount);
end;

```

How can I save this into a stream or a file to be loaded back? I have tried using `MyTree.SaveToFile('C:/Test.dat')` and `MyTree.LoadFromFile('C:/Test.dat')`, but when it's loaded back the tree view contains no data, only a blank row.

Answer: 
You need to set OnLoadNode and OnSaveNode procedures for your TSVTree and implement your logic here. You can look at Project2 in the Demos folder. E.g.:

```
uses
  uSvHelpers;

MyTree.OnSaveNode := DoSave;
MyTree.OnLoadNode := DoLoad;

procedure TForm1.DoLoad(Sender: TSVTree<TMainData>; Node: TSVTreeNode<TMainData>; Stream: TStream);
var
  obj: TMainData;
begin
  //
  if Assigned(Node) then
  begin
    //read from stream
    //read in correct order
    obj.Name := Stream.AsString;
    obj.Email := Stream.AsString;
    obj.Password := Stream.AsString;
    Node.FValue := obj;
  end;
end;

procedure TForm1.DoSave(Sender: TSVTree<TMainData>; Node: TSVTreeNode<TMainData>; Stream: TStream);
begin
  if Assigned(Node) then
  begin
    //read from stream
    Stream.WriteString(Node.FValue.Name);
    Stream.WriteString(Node.FValue.Email);
    Stream.WriteString(Node.FValue.Password);
  end;
end;

```

After that you can just call `MyTree.SaveToFile('C:/Test.dat')` or `MyTree.LoadFromFile('C:/Test.dat')`. In my demo and this example i've used another unit (uSvHelpers) which implements TStream helper for more OO stream support. You can of course use your own way to write your data information to stream.
Looks like you need to implement the OnSaveNode and OnLoadNode events:

```
procedure TForm.VTLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
begin
  // Load Node Data record from the stream
end;

procedure TForm.VTSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
begin
  // Save Node Data record to the stream
end;

```