2012-07-20 28 views
2

我在窗体上有2个控件,TCheckBox和TEdit。如何编写基于TCheckBox.Checked控制TEdit.PasswordChar的活动绑定表达式?

我想使用Live绑定执行此:

  1. 当TCheckBox.Checked =真,设置TEdit.PasswordChar = *
  2. 当TCheckBox.Checked =假,设置TEdit.PasswordChar =#0

我该如何编写ControlExpression来实现这个功能?如果我可以避免注册自定义方法,那将是非常好的。

+4

更好的分配复选框,一个动作,写上执行 “本地” 代码。也许在某些情况下使用活动绑定有一个原因,但它们绝对不适合懒惰的程序员;) – Marcodor 2012-07-20 05:54:08

回答

2

下面是一个简单的例子。我找不到一个布尔表达式求值器,所以我注册了一个新的求解器,并且还有一个字符串到字符转换器(似乎也丢失了)。

形式:

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. 
+4

这个例子显示了活结合设计有多荒谬。写大量的代码和**仍**必须实施OnClick事件。 – 2012-07-20 10:10:42

+0

你不必**执行'OnClick'事件处理程序,如下所示。还有其他可能性(例如'Application.OnIdle'带有通用代码来自动重新评估所有活动绑定,类似于Actions)。 – 2012-07-20 10:25:20

+0

更糟。组件应该具有约束力,并且理论上它们是因为它们支持使用数据集afaik时使用的bindlink。但它不适用于组件到组件或组件到简单的数据对象绑定。 – 2012-07-20 11:02:46