动态

详情 返回 返回

一步一步學習使用LiveBindings(9) LiveBindings圖像綁定與自定義綁定方法(2) - 动态 详情

這是《一步一步學習使用LiveBindings(8)》的接續,本章將學習如下知識點:

  • 為TGrid應用列格式。
  • 創建自定義的綁定方法。
  • 實現表單級別的格式化方法。

上一節使用嚮導將TGrid綁定到ProtoTypeBindSource,它會創建TLinkGridToDataSource這個綁定鏈接。嚮導創建的綁定只是將PrototypeBindSource1的*與TGrid的*進行了綁定,這種綁定模式在運行時會自動創建Column,所以設計時沒有辦法去操控列。
綁定的正確方式應該是在PrototypeBindSource1的Field與TGrid的Column進行綁定,

1. Grid的列格式化

如果需要對單獨的列進行操作,可以使用兩種方法:

  1. 選中LinkGridToDataSourcePrototypeBindSource1,然後在屬性編輯器中選擇“Columns”屬性,單擊右側的按鈕,打開列編輯器,在這裏手動添加新的列,並設置DataMember為相應的字段,或者單擊“Add All Fields”按鈕,將一次性添加所有的字段。

img

  1. 在LiveBindings Designer中將Field直接拖動到TGrid上,完成綁定操作。

img

在完成後,在LiveBindings Designer選中任意一條連接線,屬性面板上均只顯示LinkGridToDataSourcePrototypeBindSource1這個綁定鏈接,因此如果要添加公式,需要在屬性面板中,打開Columns編輯器,選中某一個具體的Column進行設置。

每一個Column具有如下的一些屬性:

  • ColumnStyle : 默認情況下,列被創建為 TStringColumn 。但是,您可能希望選擇一個與其內容相關的更好值(數字、日期值等)。
  • CustomFormat : 此屬性允許您指定用於在網格中渲染值的表達式。
  • CustomParse : 此屬性允許您指定用於將用户輸入的值轉換為列的適當值的表達式。
  • Header : 該屬性設置列的標題。
  • MemberName : 該屬性設置列的對應字段。
  • ReadOnly : 該屬性定義列是否可以被用户編輯。
  • Visible : 該屬性設置列的可見性(你可以創建列,然後決定每列的可見性)。
  • Width : 該屬性指定列的寬度。
    CustomFormat和CustomParse格式表達式,與本系列在《一步一步學習使用LiveBindings(8)》中介紹的使用方式完全相同。
    下圖是接下來實現的效果:

img

這裏為HireDate列應用了日期格式化,
CustomFormat:

FormatDateTime('MMMM yyyy',self.Value)

Salary列應用了貨幣格式化。
CustomFormat:

Format('%%m', self.Value + 0.0)

CustomParse:

SubString(%s, 1, 15)

在Grid最後添加了2列,一列是薪資等級,如果薪資高的,就加了一個綠色向上的手勢,如果薪資不是那麼高的,就加了一個綠色的手勢。看上去就顯得專業多了。

要實現這樣的目的,在這裏添加了2個新的列,一個列的ColumnStyle指定為GlyphColumn,另一個列指定為ProgressColumn列類型。

注意:雖然屬性編輯器中,ColumnStyle下拉框並沒有提供一個ProgressColumn類型,但仍然可以通過輸入ProgressColumn來顯示進度條。

GlyphColumn可以顯示來自TImageList控件中的圖片,因此在主窗體上添加了一個TImageList控件,將TGrid的Images屬性指向它。
在這個ImageList控件中,僅放了2張圖片,分別是2個手勢,因此其ImageIndex分別為0和1。在CustomFormat中,寫下如下的公式:

IfThen(Self.Value>60000, 0, 1)

如果年薪大於6萬,則認為是高薪了,打個綠色的手勢,否則顯示紅色的手勢。

ProgressColumn將使用表達式給它一個當前最高薪資的比率。如果是Manager,則最高薪資為20萬,否則最高薪資設為10萬。公式如下:

100*(Self.Value /IfThen(Owner.Title.Value='Manager', 200000, 100000) )

可以看到在表達式中又套用了表達式,這個可以靈活應用。

2. 自定義綁定方法

貨幣格式目前的解析公式不能滿足需求,SubString(%s, 1, 15)雖然簡單的移除了前綴的貨幣符號,但是對於數字中的分隔符號就不能識別,因此會發生錯誤。系統內置的方法並沒有好的解決方案,好在還可以創建自定義的綁定方法。

請按下面的步驟實現自定義的綁定方法:

1. 單擊主菜單中的 File > New > Package ,創建一個新的Delphi包。

建議立即單擊工具欄上的Save All按鈕,將包保存為CurrencyBindingMethod.dproj。

然後在包中添加一個新的Unit,保存為Methods.FormatCurrency.pas。

創建自定義綁定方法需要調用System.Bindings.Methods單元中的MakeInvokable方法,它返回定義在System.Bindings.EvalProtocol單元中的IInvokable接口,需要在uses區中添加對這2個單元的引用。

完整代碼如下所示,請參考代碼步驟:

unit Methods.FormatCurrency;

interface

uses
  SysUtils;

implementation

uses
  //MakeInvokable 函數、 TMethodDescription 類型定義和 TBindingsMethodFactory 單例
  System.Bindings.Methods,
  //IValue,TValueWrapper 和 IInvokable 類型定義
  System.Bindings.EvalProtocol;

//將貨幣類型專換為字符串類型
function CurrencyToStrInvokable: IInvokable;
begin
  Result := MakeInvokable(
    function (Args: TArray<IValue>): IValue
    var
       AValue:Currency;
       CurrencyStr:string;
    begin
      // 1 - 輸入參數識別並進行驗證
      if Length(Args) < 1 then
        raise EEvaluatorError.Create('CurrencyToStr: 至少需要一個參數');
      // 2 - 調用真實的轉換CurrToStrF方法
        AValue:=Args[0].GetValue.AsCurrency;
        CurrencyStr:= CurrToStrF(AValue, ffCurrency, 2);
      // 3 - 將結果值打包為TValueWrapper
      Exit(TValueWrapper.Create(CurrencyStr));
    end
  );
end;

//將字符串類型專換為貨幣類型。
function StrToCurrencyInvokable: IInvokable;
begin
  Result := MakeInvokable(
    function (Args: TArray<IValue>): IValue
    var
       AValue:String;
       CurrencyVal:Currency;
       C: char;
       LDigits: string;
    begin
      // 1 - 輸入參數識別並進行驗證
      if Length(Args) < 1 then
        raise EEvaluatorError.Create('StrToCurrency: 至少需要一個參數');
      // 2 - 將參數轉換為真實的參數類型,再進行實際的業務處理
        AValue:=Args[0].GetValue.AsString;
        for C in AValue do
          case C of
           '0'..'9',
           '.':
             LDigits := LDigits + C;
          end;
      CurrencyVal := StrToCurr(LDigits);
      // 3 - 將結果裝包裝起來
      Exit(TValueWrapper.Create(CurrencyVal));
    end
  );
end;

initialization
  // 4 -  註冊方法
  TBindingMethodsFactory.RegisterMethod(
    TMethodDescription.Create(
        CurrencyToStrInvokable
      , 'CurrencyToStr', 'CurrencyToStr', '', True
      , '貨幣轉換為字符串'
      , nil
    )
  );

  TBindingMethodsFactory.RegisterMethod(
    TMethodDescription.Create(
        StrToCurrencyInvokable
      , 'StrToCurrency', 'StrToCurrency', '', True
      , '字符串轉換為貨幣'
      , nil
    )
  );

finalization
// 5 - 卸載已經註冊的方法
  TBindingMethodsFactory.UnRegisterMethod('CurrencyToStr');
  TBindingMethodsFactory.UnRegisterMethod('StrToCurrency');

end.

可以看到,代碼中定義了CurrencyToStr和StrToCurrency這兩個方法,它們都接收一個參數,並且調用了SysUtil中的CurrToStrF和StrToCurr函數進行了轉換。

2. 在Project Manager窗口右擊CurrencyBindingMethod項目名稱,先Build一次,再單擊"Install"菜單項進行安裝。

img

安裝完成後,回到LiveBindings_BindFormat.dproj項目,選中TBindingList控件,在屬性編輯器中找到Methods屬性,單擊右側的按鈕,可以看到CurrencyToStr和StrToCurrency這兩個方法已經出現在了列表中。

img

3. 要讓我們自己的項目能夠正確識別這2個方法,還需要將包中的Methods.FormatCurrency.pas單元添加到uMainForm.pas的uses區,否則會提示方法無法找到的錯誤。

請在Project > Options > Delphi Compiler > Search Path路徑中添加了對Package代碼的引用。

img

在uses區中添加如下的引用:

implementation

{$R *.fmx}

uses
  System.Bindings.Helper, System.Bindings.Methods,
    System.Bindings.EvalProtocol,Methods.FormatCurrency;

將Salary的公式改為如下:

CustomFormat:

CurrencyToStr(self.Value)

CustomParse

StrToCurrency(%s)

經過這樣的處理,現在在貨幣的顯示和輸入上,就非常理想了,如下圖所示:

img

4. 使用自定義的格式化方法

在《一步一步學習使用LiveBindings(8)》中曾經介紹過通過self.owner.owner,返回到了主窗體TMainForm,我們在主窗體上定義了一個屬性MyProgName,可以通過self.owner.owner.MyProgName訪問到此屬性。同理,還可以在主窗體上定義一個函數,通過self.owner.owner進行訪問,實現自定義的格式化方法。

實現過程如下:

1. 首先在uMainForm的public區定義了一個函數,實現根據指定的格式化字符串格式化數字,定義與實現如下所示:

  public
    { Public declarations }
    property MyProgName:string read GetProgName;

    //根據指定的格式化字符串或區域格式化符點數。
    function FormFormatFloat(const AFormat: string; const AValue: Extended; const ALocale: string): string;
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.fmx}

uses
  System.Bindings.Helper, System.Bindings.Methods,
    System.Bindings.EvalProtocol,Methods.FormatCurrency;

function TfrmMain.FormFormatFloat(const AFormat: string; const AValue: Extended;
  const ALocale: string): string;
var
  LFormatSettings: TFormatSettings;
begin
  LFormatSettings := FormatSettings;
  if not ALocale.IsEmpty then
    LFormatSettings := TFormatSettings.Create(ALocale);
  Result := FormatFloat(AFormat, AValue, LFormatSettings);
end;

接下來,我使用LiveBindings Wizard嚮導新建了一個TEdit指向Salary的鏈接,然後為這個TEdit的綁定鏈接指定CustomFormat如下,使其保留4位小數:

Self.Owner.Owner.FormFormatFloat('#,#0.0000', self.Value, '') 

效果如下:

img

可以看到,果然正確的實現了格式化顯示。

右邊的那個手勢圖標,是一個TGlyph組件,它可以連接到一個TImageList控件,通過在LiveBindings Designer中,將Salary綁定到其ImageIndex屬性。最後應用瞭如下的公式:

IfThen(Self.Value>60000, 0, 1)

img

總結

本文介紹了格式化的幾種進階方法:

  • 使用表達式列格式化。
  • 自定義綁定方法。
  • 使用自定義表單方法格式化。

強烈推薦使用自定義綁定方法,不是很推薦自定義表單方法,但有時候表單級別的方法能解決很多業務邏輯相關的格式化問題。所以具體如何架構,還是要具體問題,具體分析。

Add a new 评论

Some HTML is okay.