Delphi 如何基于TCheckBox.Checked编写控制TEdit.PasswordChar的活动绑定表达式?
我在表单上有两个控件,TCheckBox和TEdit 我想使用Live Binding执行以下操作:Delphi 如何基于TCheckBox.Checked编写控制TEdit.PasswordChar的活动绑定表达式?,delphi,livebindings,Delphi,Livebindings,我在表单上有两个控件,TCheckBox和TEdit 我想使用Live Binding执行以下操作: 当TCheckBox.Checked=True时,设置TEdit.PasswordChar=* 当TCheckBox.Checked=False时,设置TEdit.PasswordChar=#0 如何编写ControlExpression来实现这一点?如果我可以避免注册自定义方法,那就太好了。这里有一个简单的例子。我找不到布尔表达式计算器,所以我注册了一个新的计算器,还有一个字符串到字符的转换器
如何编写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
对象格式1:t格式1
左=0
Top=0
标题='Form1'
ClientHeight=282
ClientWidth=418
颜色=clBtnFace
Font.Charset=默认字符集
Font.Color=clWindowText
字体高度=-11
Font.Name='Tahoma'
Font.Style=[]
OldCreateOrder=False
PixelsPerInch=96
text高度=13
对象复选框1:t复选框
左=24
Top=24
宽度=97
高度=17
标题='CheckBox1'
TabOrder=0
OnClick=CheckBox1Click
结束
对象Edit1:TEdit
左=24
Top=56
宽度=121
高度=21
TabOrder=1
Text='Edit1'
结束
对象绑定列表1:TBindingsList
方法=
输出转换器=
UseAppManager=True
左=212
Top=13
对象BindExpression1:TBindExpression
类别='绑定表达式'
ControlComponent=Edit1
SourceComponent=CheckBox1
SourceExpression='iif(选中,#39'*'#39','#39#39')'
ControlExpression='PasswordChar'
NotifyOutputs=True
方向=方向源控制
结束
结束
结束
以及守则:
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.
单元1;
接口
使用
Winapi.Windows、Winapi.Messages、System.SysUtils、System.Variants、System.Classes、Vcl.Graphics、,
Vcl.控件、Vcl.窗体、Vcl.对话框、Vcl.StdCtrls、Data.Bind.EngExt、Vcl.Bind.DBEngExt、System.Rtti、,
Vcl.Bind.Editors、Data.Bind.Components、System.Bindings.Outputs;
类型
TForm1=类(TForm)
复选框1:t复选框;
编辑1:TEdit;
绑定列表1:t绑定列表;
BindExpression1:TBindExpression;
程序检查框1单击(发送方:ToObject);
私有的
{私有声明}
公众的
{公开声明}
结束;
变量
表1:TForm1;
实施
{$R*.dfm}
使用
System.TypInfo,
System.Bindings.EvalProtocol,
System.Bindings.Methods;
资源字符串
sIifArgError='Iif()调用需要三个变量';
sIifExpectedBoolean='Iif()的第一个参数必须是布尔值';
函数MakeIif:IInvokable;
开始
结果:=MakeInvokable(
函数(Args:TArray):IValue
变量
五:伊瓦鲁;;
B:布尔型;
开始
如果长度(Args)为3,则
提高EEvaluatorError.Create(sIifArgError);
V:=Args[0];
如果是(V.GetType^.Kind tkEnumeration)或(V.GetType^.Name'Boolean'),则
提高EEEvaluatorError.Create(sIifExpectedBoolean);
B:=V.GetValue.AsBoolean;
如果B那么
结果:=TValueWrapper.Create(参数[1].GetValue)
其他的
结果:=TValueWrapper.Create(Args[2].Getvalue);
结束
);
结束;
程序TForm1.复选框1单击(发送方:TObject);
开始
BindingsList1.Notify(CheckBox1,“Checked”);
结束;
初始化
TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create(MakeIif,'iif','iif','iif','',True','nil));
TValueRefConverterFactory.RegisterConversion(类型信息(字符串)、类型信息(字符),
TConverterDescription.Create(
过程(常数I:TValue;变量O:TValue)
变量
S:字符串;
开始
S:=I.AsString;
如果长度=1,则
O:=S[1]
其他的
O:=#0;
完,,
“StringToChar”、“StringToChar”、“True”、“nil”);
定稿
TValueRefConverterFactory.UnRegisterConversion('StringToChar');
TBindingMethodsFactory.UnRegisterMethod('iif');
结束。
最好将复选框指定给操作,并在执行时编写“本机”代码。也许在某些情况下使用实时绑定是有原因的,但它们肯定不是为懒惰的程序员准备的;)这个例子显示了livebinding设计是多么荒谬。编写大量代码,但仍然必须实现OnClick事件。您不必实现OnClick
事件处理程序,如图所示。还有其他可能性(例如,Application.OnIdle
,使用通用代码自动重新评估所有活动绑定,类似于操作),甚至更糟。组件应该具有绑定意识,理论上是这样的,因为它们支持在处理afaik数据集时使用的bindlink。但它不能正确处理组件到组件或组件到简单数据对象的绑定。同意,更好的方法是在源组件更改时自动计算所有绑定。也许这可以通过某种RTTI钩子来完成。编写OnChange事件处理程序是可以的,因为它可能有很大的机会被许多控件共享。绑定方法促进了代码重用,并可能大大减少.pas文件中的代码,从而将重点放在UI控件交互以外的逻辑上。