Delphi FireMonkey中TEdit派生类创建关联对象失败求助
Fixing TMyEdit Sync Issues with Self-Created MyString Instance
Let's break down why your TMyEdit isn't working correctly when it creates its own MyString, and walk through the fixes step by step.
Key Issues in Your Code
- Global vs. Internal MyString Instance Mismatch: When TMyEdit creates its own MyString, it's stored in the private
fMyStringfield of the edit control—not the globalMystringvariable. So when you check the global variable later, it's stillnil. - Private Value Property: Your
TMyStringclass has a privatevalueproperty, which means external code (like your button click handlers) can't actually access it—this should cause a compile error. - Incorrect OnChange Override: You redeclared the
OnChangeproperty in TMyEdit, which hides the base TEdit's OnChange event and breaks the default text change trigger logic. - One-Way Sync Only: Your current code only syncs TEdit text to MyString, but doesn't handle the reverse (MyString changes updating the TEdit).
Fixed Implementation
Step 1: Update TMyString for External Access and Change Notifications
First, make the value property public and add an OnChange event to support two-way sync:
type TMyString = class(TObject) private fValue: string; fOnChange: TNotifyEvent; procedure SetValue(const Value: string); public property Value: string read fValue write SetValue; property OnChange: TNotifyEvent read fOnChange write fOnChange; end; procedure TMyString.SetValue(const Value: string); begin if fValue <> Value then begin fValue := Value; // Notify listeners when the value changes if Assigned(fOnChange) then fOnChange(Self); end; end;
Step 2: Fix TMyEdit to Handle Sync Properly
Remove the custom OnChange property, use the base TEdit's event, and add two-way sync logic:
TMyEdit = class(TEdit) constructor Create(AOwner: TComponent); override; private fMyString: TMyString; procedure EditChanged(Sender: TObject); procedure MyStringChanged(Sender: TObject); procedure SetMyString(const Value: TMyString); public property MyProperty: TMyString read fMyString write SetMyString; procedure LoadFromMyString; end; constructor TMyEdit.Create(AOwner: TComponent); begin inherited Create(AOwner); // Bind the base TEdit's OnChange event to our handler inherited OnChange := EditChanged; end; procedure TMyEdit.EditChanged(Sender: TObject); begin if not Assigned(fMyString) then begin // Create internal MyString if none exists fMyString := TMyString.Create; // Bind its change event to sync back to the edit fMyString.OnChange := MyStringChanged; end; fMyString.Value := Self.Text; end; procedure TMyEdit.MyStringChanged(Sender: TObject); begin // Sync MyString value back to the edit control if Sender is TMyString then Self.Text := TMyString(Sender).Value; end; procedure TMyEdit.LoadFromMyString; begin if Assigned(fMyString) then Self.Text := fMyString.Value; end; procedure TMyEdit.SetMyString(const Value: TMyString); begin if fMyString <> Value then begin // Unbind old MyString's event if Assigned(fMyString) then fMyString.OnChange := nil; fMyString := Value; // Bind new MyString's event for reverse sync if Assigned(fMyString) then fMyString.OnChange := MyStringChanged; LoadFromMyString; end; end;
Step 3: Update Form Logic to Handle Both Scenarios
Adjust your button handlers to check the TMyEdit's internal MyString (not just the global variable) and sync properly:
procedure TForm1.Button1Click(Sender: TObject); begin Myedit1 := TMyEdit.Create(Form1); Myedit1.Parent := Form1; Myedit1.Position.X := 10; Myedit1.Position.Y := 10; Myedit1.Width := 200; // Use global MyString if it exists, else let TMyEdit create its own if Assigned(Mystring) then Myedit1.MyProperty := Mystring; MyEdit1.Text := 'any text'; Myedit1.EditChanged(Self); // Trigger initial sync end; procedure TForm1.Button2Click(Sender: TObject); begin // Check TMyEdit's internal MyString first if Assigned(Myedit1.MyProperty) then Button2.Text := Myedit1.MyProperty.Value else Button2.Text := 'MyString not created'; // Optional: Check global MyString separately if Assigned(Mystring) then ShowMessage('Global MyString value: ' + Mystring.Value) else ShowMessage('Global MyString not created'); end; procedure TForm1.Button3Click(Sender: TObject); begin // Clean up existing global MyString if needed if Assigned(Mystring) then Mystring.Free; Mystring := TMyString.Create; Mystring.Value := '123'; // Assign global MyString to TMyEdit if it exists if Assigned(Myedit1) then Myedit1.MyProperty := Mystring; end;
How This Fixes Your Problem
- Two-Way Sync: Now changes to either the TEdit text or MyString value will sync to the other.
- Correct Instance Handling: TMyEdit's
MyPropertyexposes both externally provided and self-created MyString instances, so you can check it directly instead of relying solely on the global variable. - Proper Event Binding: We use the base TEdit's OnChange event instead of hiding it, ensuring text changes trigger the sync logic reliably.
内容的提问来源于stack exchange,提问作者costateixeira
相关产品推荐
相关产品推荐

