如何编写基于TCheckBox.Checked的控制TEdit.PasswordChar的实时绑定表达式



我在一个窗体上有两个控件,TCheckBox和TEdit。

我想使用Live Binding来执行以下操作:

  1. 当TCheckBox.Checked=True时,设置TEdit.PasswordChar=*
  2. 当TCheckBox.Checked=False时,将TEdit.PasswordChar设置为#0

如何编写ControlExpression来实现这一点?如果我能避免注册自定义方法,那就太好了。

这里有一个简单的例子。我找不到布尔表达式计算器,所以我注册了一个新的计算器,还有一个字符串到字符的转换器(似乎也不见了)。

形式:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 282
  ClientWidth = 418
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object CheckBox1: TCheckBox
    Left = 24
    Top = 24
    Width = 97
    Height = 17
    Caption = 'CheckBox1'
    TabOrder = 0
    OnClick = CheckBox1Click
  end
  object Edit1: TEdit
    Left = 24
    Top = 56
    Width = 121
    Height = 21
    TabOrder = 1
    Text = 'Edit1'
  end
  object BindingsList1: TBindingsList
    Methods = <>
    OutputConverters = <>
    UseAppManager = True
    Left = 212
    Top = 13
    object BindExpression1: TBindExpression
      Category = 'Binding Expressions'
      ControlComponent = Edit1
      SourceComponent = CheckBox1
      SourceExpression = 'iif(Checked, '#39'*'#39', '#39#39')'
      ControlExpression = 'PasswordChar'
      NotifyOutputs = True
      Direction = dirSourceToControl
    end
  end
end

代码:

unit Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Data.Bind.EngExt, Vcl.Bind.DBEngExt, System.Rtti,
  Vcl.Bind.Editors, Data.Bind.Components, System.Bindings.Outputs;
type
  TForm1 = class(TForm)
    CheckBox1: TCheckBox;
    Edit1: TEdit;
    BindingsList1: TBindingsList;
    BindExpression1: TBindExpression;
    procedure CheckBox1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
uses
  System.TypInfo,
  System.Bindings.EvalProtocol,
  System.Bindings.Methods;
resourcestring
  sIifArgError = 'Expected three variables for Iif() call';
  sIifExpectedBoolean = 'First argument to Iif() must be a boolean';
function MakeIif: IInvokable;
begin
  Result := MakeInvokable(
    function(Args: TArray<IValue>): IValue
    var
      V: IValue;
      B: Boolean;
    begin
      if Length(Args) <> 3 then
        raise EEvaluatorError.Create(sIifArgError);
      V := Args[0];
      if (V.GetType^.Kind <> tkEnumeration) or (V.GetType^.Name <> 'Boolean') then
        raise EEvaluatorError.Create(sIifExpectedBoolean);
      B := V.GetValue.AsBoolean;
      if B then
        Result := TValueWrapper.Create(Args[1].GetValue)
      else
        Result := TValueWrapper.Create(Args[2].Getvalue);
    end
  );
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  BindingsList1.Notify(CheckBox1, 'Checked');
end;
initialization
  TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create(MakeIif, 'iif', 'iif', '', True, '', nil));
  TValueRefConverterFactory.RegisterConversion(TypeInfo(string), TypeInfo(Char),
    TConverterDescription.Create(
      procedure(const I: TValue; var O: TValue)
      var
        S: string;
      begin
        S := I.AsString;
        if Length(S) = 1 then
          O := S[1]
        else
          O := #0;
      end,
      'StringToChar', 'StringToChar', '', True, '', nil));
finalization
  TValueRefConverterFactory.UnRegisterConversion('StringToChar');
  TBindingMethodsFactory.UnRegisterMethod('iif');
end.

最新更新