Hi
Ich arbeite mit XML-Dateien welche ich über TXMLTransform und TClientDataSet in einem VirtualTreeView darstelle.
Die Darstellung funktioniert ohne Probleme.
Aber sobald ich Daten in der XML-Datenbank ändere kommt es zu Zugriffsverletzungen da TBookmarks ungültig werden.
Ich hab ein Testprojekt erstellt um den Fehler leichter zu finden.
Hier der Quelltext:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, VirtualTrees, DB, DBClient, xmldom, Provider, Xmlxform, Grids, DBGrids;
type
PNodeData = ^TNodeData; TNodeData = record FBookmark: TBookmark; end;
TForm1 = class(TForm) VST: TVirtualStringTree; btnLoad: TButton; ClientDataSet: TClientDataSet; XMLTransformProvider: TXMLTransformProvider; DataSource: TDataSource; DBGrid1: TDBGrid; btnAdd: TButton; procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString); procedure btnLoadClick(Sender: TObject); procedure VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); procedure btnAddClick(Sender: TObject); procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); private public end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnAddClick(Sender: TObject); var Node: PVirtualNode; NodeData: PNodeData; begin ClientDataSet.Append; ClientDataSet.FieldValues['test'] := '123'; ClientDataSet.Post;
Node := VST.AddChild(nil); NodeData := VST.GetNodeData(Node); NodeData^.FBookmark := ClientDataSet.GetBookmark; end;
procedure TForm1.btnLoadClick(Sender: TObject); var Node: PVirtualNode; NodeData: PNodeData; begin XMLTransformProvider.XMLDataFile := 'test.xml'; ClientDataSet.XMLData := XMLTransformProvider.TransformRead.Data; ClientDataSet.DisableControls; try ClientDataSet.First; while not ClientDataSet.Eof do begin Node := VST.AddChild(nil); NodeData := VST.GetNodeData(Node); NodeData^.FBookmark := ClientDataSet.GetBookmark; ClientDataSet.Next; end; finally ClientDataSet.EnableControls; end; end;
procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); begin NodeDataSize := SizeOf(PNodeData); end;
procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString); begin ClientDataSet.GotoBookmark(TBookmark(PNodeData(Sender.GetNodeData(Node)).FBookmark)); CellText := ClientDataSet.FieldByName('test').asString; end;
procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: WideString); var NodeData: PNodeData; begin ClientDataSet.GotoBookmark(TBookmark(PNodeData(Sender.GetNodeData(Node)).FBookmark)); ClientDataSet.Edit; ClientDataSet.FieldValues['test'] := NewText; ClientDataSet.Post; ClientDataSet.GotoBookmark(TBookmark(PNodeData(Sender.GetNodeData(Node)).FBookmark)); end;
end. |
Die XML-Datei wird mit klick auf "Load" geladen.
Mit "Add" werden Datensätze hinzugefügt.
Klickt man nun zweimal auf einen Knoten und ändert dessen Beschriftung kommt es zur Zugriffsverletzung:
| Zitat: |
| Im Projekt Project1.exe ist eine Exception der Klasse EDatabaseError mit der Meldung 'ClientDataSet: Datensatz nicht gefunden' aufgetreten. |
Dies passiert jedoch nur bei neu hinzugefügten Knoten und auch nicht dem zuletzt hinzugefügtem Knoten.
Entkommentiert man Zeile 104 und 105 passiert dieser Fehler nicht mehr und alles funktioniert.
Dort wird nach dem Bearbeiten das TBookmark des Datensatzes erneut dem Knoten zugewiesen.
Nun bin ich mir nicht sicher ob das eine saubere Lösung ist, nach jedem Bearbeiten den TBookmark neu zuzuweißen.
Vielleicht ist der Fehler ja auch woanders?
Hab das Projekt angehängt.
Edit//
ich machs jetzt mit findkey.
das klappt besser.