我正在使用Zarko Gajic将更多(自定义)数据存储到树视图的树节点中为每个节点项添加其他字符串,但我发现如果我的应用程序已经闲置了很长时间,那么我拥有的值存储在自定义树节点中的节点消失.
这就是我昨天离开时的定制treenode

这就是今天早上的样子(注意fMyProperty值现在为空)

我已经确认我的计算机从未休眠或睡眠,但系统会在锁定1分钟后关闭显示器以节省电量.然而,计算机需要闲置一段时间才能发生此问题.它在夜间闲置时最明显,但如果只闲置30分钟则不太可能发生.
我能想到的唯一可能导致这种情况的是操作系统将应用程序内存交换到磁盘,当您重新激活计算机时,它会被换回内存.正如您所看到的,FItemId正在发生变化,因此它似乎正在"重建"Treeview,从而失去与自定义Tree节点的关联.
我用一个非常简单的应用程序重现了这个问题,其代码如下.
我知道我可以使用另一种方法来存储额外的数据,通过使用Treenode中的数据字段,但是能够这样做会很好,因为我不必担心在删除节点时释放额外的内存块.
我该怎么做才能防止这种数据丢失?
unit Test04Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls;
type
  TMyTreeNode = class(TTreeNode)
    private
      fMyProperty : string;
    public
    property MyProperty : string read fMyProperty write fMyProperty;
  end;
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    StatusBar1: TStatusBar;
    procedure FormCreate(Sender: TObject);
    procedure TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
  private
    fTreeView1_Selected: TMyTreeNode;
    property TreeView1_Selected : TMyTreeNode read fTreeView1_Selected;
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
  tn : TTreeNode;
  cnt : integer;
begin
  //fill some items
  TreeView1.Items.Clear;
  for cnt := 0 to 9 do
  begin
    tn := TreeView1.Items.AddChild(nil, IntToStr(cnt));
    //add default MyProperty values
    TMyTreeNode(tn).MyProperty := 'this is node ' + IntToStr(cnt);
  end;
end;
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  fTreeView1_Selected := TMyTreeNode(Node);
  StatusBar1.Panels[0].Text := TreeView1_Selected.MyProperty;
end;
procedure TForm1.TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);
begin
  NodeClass := TMyTreeNode;
end;
end.
在Windows 2012 R2上使用Delphi XE6,调试Win32版本,但Win64版本也会出现此问题.
这是因为重新创建VCL窗口而发生的.VCL设计意味着在某些情况下,需要重新创建实现表单和控件的窗口.通常,当进行状态更改而无法应用于已存在的窗口时,会发生这种情况.因此窗口被重新创建.发生这种情况时,控件会尝试保存其状态,然后将其还原.
对于树视图,节点本身将被销毁,然后重新创建.这意味着在参考节点时需要格外小心.一旦窗口重新创建,该节点引用就无效.
您可以通过调用RecreateWnd树视图控件的受保护方法来强制执行此操作.你需要受保护的成员访问黑客来做到这一点.但是一旦打电话,RecreateWnd您就会发现自定义节点的属性已被清除.确实将重写的构造函数和析构函数添加到节点类中,并观察它们在重新创建期间被调用.  
你在这里很难过.存储然后恢复节点状态的树视图重新创建代码,没有任何钩子,据我所见.您的自定义节点将被销毁,并将重新创建.我认为在此过程中您没有直接的方法来保持节点的状态.该Data属性是持久的,因此您可以使用它来确保正确地重新创建自定义节点.但是,一旦你走上这条道路,自定义节点会带来哪些好处?
我的建议是您使用Data自定义数据并避免使用自定义节点类型.
据我所知,这个问题使自定义节点类型功能接近无用.
| 归档时间: | 
 | 
| 查看次数: | 594 次 | 
| 最近记录: |