2017-03-17 44 views
0

我有一个自定义控件,它需要在运行时根据已发布的属性加载时执行一些操作。但是,我遇到了一个问题,无论何时我检查已发布的属性,它尚未设置,并始终是默认值。何时在运行时分配了已发布的属性?

我第一次尝试检查控件的构造函数中的属性,但很快发现它们尚未加载。我知道,当控件显示在屏幕上时,属性设置是正确的,因此它不是一个根本没有加载属性的问题。

我接下来试图覆盖Loaded Method但我仍然有同样的问题,所以我不认为这正是我正在寻找的。

void __fastcall TFmSearchBar::Loaded() 
{ 
    TEdit::Loaded(); //call base class loaded 

    if(MyProperty) 
    { 
     //do stuff 
    } 
} 

这些发布的属性在哪些点实际设置?

只要属性设置正确,我可以根据这些属性执行一些逻辑以应对哪些方法?

+0

“*我仍然有同样的问题*” - 这究竟是什么?你没有解释你的实际问题是什么。 –

回答

1

如果我在控件的构造函数中检查属性,即使我在设计器中另有指定,该属性也始终是默认值。

正确,因为它的设计时间值尚未分配。

这些发布的属性在哪些点实际设置?

正在构建所有者(表单,框架或数据模块)时。它加载自己的DFM资源并解析它,构建存储的子组件并读取它们的属性值。

例如,假设您有以下DFM:

object Form1: TForm1 
    Left = 0 
    Top = 0 
    Caption = 'Form1' 
    ... 
    object Edit1: TEdit 
    Left = 136 
    Top = 64 
    Width = 121 
    Height = 21 
    TabOrder = 0 
    end 
    object Button1: TButton 
    Left = 263 
    Top = 62 
    Width = 75 
    Height = 25 
    Caption = 'Button1' 
    TabOrder = 1 
    end 
end 

的DFM流处理大致转换为下面的等价代码(我留下了大量的内部细节进行了简单):

__fastcall TCustomForm::TCustomForm(TComponent *Owner) 
    : TScrollingWinControl(Owner) 
{ 
    this->FFormState << fsCreating; 
    try 
    { 
     // locate, load, and parse the "Form1" DFM resource ... 

     this->FComponentState << csLoading; 
     this->Parent = ...; 
     this->Name = L"Form1": 
     this->FComponentState << csReading; 
     this->Left = 0; 
     this->Top = 0; 
     this->Caption = L"Form1"; 
     ... 

     TEdit *e = new TEdit(this); 
     try 
     { 
      e->FComponentState << csLoading; 
      e->Parent = this; 
      e->Name = L"Edit1"; // <-- sets the derived Form's 'Edit1' member to this object 
      e->FComponentState << csReading; 
      e->Left = 136; 
      e->Top = 64; 
      e->Width = 121; 
      e->Height = 21; 
      e->TabOrder = 0; 
      e->FComponentState >> csReading; 
     } 
     catch (...) 
     { 
      delete e; 
      throw; 
     } 

     TButton *b = new TButton(this); 
     try 
     { 
      b->FComponentState << csLoading; 
      b->Parent = this; 
      b->Name = L"Button1"; // <-- sets the derived Form's 'Button1' member to this object 
      b->FComponentState << csReading; 
      b->Left = 263; 
      b->Top = 62; 
      b->Width = 75; 
      b->Height = 25; 
      b->Caption = L"Button1"; 
      b->TabOrder = 1; 
      b->FComponentState >> csReading; 
     } 
     catch (...) 
     { 
      delete b; 
      throw; 
     } 

     this->FComponentState >> csReading; 

     ... 

     e->Loaded(); 
     b->Loaded(); 
     this->Loaded(); 
    } 
    __finally 
    { 
     this->FFormState >> fsCreating; 
    } 
} 

因此,正如您所看到的,组件的属性值在其构造函数被调用时不可用。

只要属性设置正确,我可以根据这些属性执行一些逻辑以执行某些逻辑?

这取决于属性需要做什么。如果他们需要立即执行操作,则可以直接在其属性设置器中执行此操作。但是,如果他们需要等到其他属性首先加载(如果一个属性取决于另一个属性的值),那么应该覆盖虚拟方法Loaded(),该方法在DFM流式传输完成后自动调用。属性设置器可以检查ComponentState属性的标志,以了解组件当前是否在设计时在表单设计器中运行,无论DFM当前是否正在流式传输等,然后根据需要采取相应措施。

我试图重写载入的方法,但我仍然有同样的问题

这到底是什么?你没有解释你的实际问题是什么。请edit your question提供这些详细信息。

所以我不认为这正是我所期待的。

它很可能是,你可能只是没有正确使用它。

+0

谢谢你的详细写作。我编辑了这个问题以更好地说明问题。 使用setters是非常有意义的,事后看来非常明显:)就Loaded方法而言,我在它们中放置了一个断点来检查我的属性值,并且当时它仍然被设置为默认值。 –

+0

@JamesHogle:'Loaded()'是覆盖的正确方法。这是流式传输系统的信号,即所有DFM属性都已流式传输并可供使用。如果这不适合你,那么其他事情正在发生。你将不得不显示不适合你的实际代码。 –