我在窗体上有2个控件,TCheckBox和TEdit。如何编写基于TCheckBox.Checked控制TEdit.PasswordChar的活动绑定表达式?
我想使用Live绑定执行此:
- 当TCheckBox.Checked =真,设置TEdit.PasswordChar = *
- 当TCheckBox.Checked =假,设置TEdit.PasswordChar =#0
我该如何编写ControlExpression来实现这个功能?如果我可以避免注册自定义方法,那将是非常好的。
我在窗体上有2个控件,TCheckBox和TEdit。如何编写基于TCheckBox.Checked控制TEdit.PasswordChar的活动绑定表达式?
我想使用Live绑定执行此:
我该如何编写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.
这个例子显示了活结合设计有多荒谬。写大量的代码和**仍**必须实施OnClick事件。 – 2012-07-20 10:10:42
你不必**执行'OnClick'事件处理程序,如下所示。还有其他可能性(例如'Application.OnIdle'带有通用代码来自动重新评估所有活动绑定,类似于Actions)。 – 2012-07-20 10:25:20
更糟。组件应该具有约束力,并且理论上它们是因为它们支持使用数据集afaik时使用的bindlink。但它不适用于组件到组件或组件到简单的数据对象绑定。 – 2012-07-20 11:02:46
更好的分配复选框,一个动作,写上执行 “本地” 代码。也许在某些情况下使用活动绑定有一个原因,但它们绝对不适合懒惰的程序员;) – Marcodor 2012-07-20 05:54:08