1

我不确定是否可能-但对我来说似乎应该是。本质上,我想在更改 StyleLookup 时触发所有组件刷新它们的样式。

我有一个 FMXComponent,它是一个名为BaseStyleLabel. 组件的StyleName属性是'BaseStyle'。它本身从样式资源中查找其样式,因此其StyleLookup属性设置为'BaseStyle1'。我也有'BaseStyle2''BaseStyle3' ...

我有一个被调用的依赖 Tlabel,MyTextLabel它的StyleLookup属性设置为BaseStyle,即 StyleName BaseStyleLabel

这一切似乎都很好。我看到它MyTextLabel继承了MyBaseStyle' BaseStyle1'的样式。

当我执行这行代码时

 BaseStyleLabel.StyleLookup := 'BaseStyle2';
 Self.repaint; // repaint whole form

我希望会BaseStyleLabel更改为“BaseStyle2”(确实如此)。然而,MyTextLabel也应该改变风格,然后看起来像'BaseStyle2',但它没有:它仍然是BaseStyle1;

限定符是 BaseLabel 和 MyTextLabel 都来自样式资源。它们实际上不是在表单上创建的组件,它们是由样式创建的。

所以我的问题是这个。

  1. 这种方法有效吗?
  2. 是否有标准方法,例如使用可以更新的样式对象?
  3. 我只是没有刷新正确的东西吗?
  4. 使用了错误的刷新方法,可能是ApplyStyle?

...编辑....下面是请求的示例...

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    MyTextLabel: TLabel;
    StyleBook1: TStyleBook;
    BaseStyleLabel: TLabel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Set up BaseStyleLabel as a Style Source
  BaseStyleLabel.StyleName := 'BaseStyle';
  // Set its Style to a Resources Style "STYLE ONE"
  BaseStyleLabel.StyleLookup := 'BaseStyle1';

 // Point MyTextLabel to whatever "BaseStyleLabel" is styled as...
   MyTextLabel.StyleLookup := 'BaseStyle'; // also says "STYLE ONE"

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //Change BaseStyle Label to "STYLE TWO" (works OK)
  BaseStyleLabel.StyleLookup := 'BaseStyle2';

  // ... BUT MyTextLabel stays as "STYLE ONE"
  // can I repaint???
  //   Auto Cascade?
  //   What about when Other TLabels are part of a different component style?

end;

end.

使用以下样式文件

object TStyleContainer
  object TLabel
    StyleName = 'BaseStyle1'
    DesignVisible = False
    Height = 17.000000000000000000
    Position.X = 521.000000000000000000
    Position.Y = 432.000000000000000000
    Text = 'STYLE ONE'
    Width = 120.000000000000000000
  end
  object TLabel
    StyleName = 'BaseStyle2'
    DesignVisible = False
    Height = 17.000000000000000000
    Position.X = 521.000000000000000000
    Position.Y = 432.000000000000000000
    Text = 'STYLE TWO'
    Width = 120.000000000000000000
  end
  object TLabel
    StyleName = 'BaseStyle3'
    Height = 17.000000000000000000
    Position.X = 521.000000000000000000
    Position.Y = 432.000000000000000000
    Text = 'STYLE 3'
    Width = 120.000000000000000000
  end
end
4

1 回答 1

0

好的 - 我一直在努力解决这个问题。

我浏览了祖先类TStyledControl。没有全局触发器导致样式查找级联。单个组件刷新其样式的事实不会导致任何组件(恰好依赖于该组件 StyleName)刷新。因此,您似乎必须手动找到所有受影响的组件并全部更新。

这对我来说还不够好,所以我为 TStyledControl 编写了一个辅助方法。

unit FMX.CascadingStyleLookup;
// Written by Glen Kleidon - 2018 - twitter: @sobaldrick4
interface

uses System.SysUtils, FMX.Types, FMX.Forms, FMX.Controls;

Type
  TCascadingStyleLookup = Class Helper for TStyledControl
    Procedure CascadeStyleLookup(AStyleLookup: String); overload;
    procedure CascadeStyleLookup(AStyleLookup: string;
      AComponent: TFMXObject); overload;
    Function FindUltimateParentForm(AChild: TFMXObject): TFMXObject;
  End;

implementation

procedure TCascadingStyleLookup.CascadeStyleLookup(AStyleLookup: String);
var
  lUltimateParent: TFMXObject;
begin
  // Apply New style to myself.
  Self.styleLookup := AStyleLookup;

  // Check if I have dependent Styles.
  if (length(Self.StyleName) = 0) then
    exit;

  // Re-Apply my own style to everything.
  lUltimateParent := Self.FindUltimateParentForm(Self);
  if lUltimateParent <> nil then
    CascadeStyleLookup(Self.StyleName, lUltimateParent);
end;

procedure TCascadingStyleLookup.CascadeStyleLookup(AStyleLookup: string;
  AComponent: TFMXObject);
var
  lChild: TFMXObject;
  lStyledControl: TStyledControl;
begin
  if (AComponent = nil) or (AComponent.Children = nil) then
    exit;

  if (AComponent.InheritsFrom(TStyledControl)) then
  begin
    lStyledControl := AComponent as TStyledControl;
    if SameText(AStyleLookup, lStyledControl.styleLookup) then
    begin
      // re-apply
      lStyledControl.styleLookup := AStyleLookup;
      // Re-cascade this style.
      if (length(lStyledControl.StyleName) > 0) and
        (NOT(SameText(lStyledControl.styleLookup, AStyleLookup))) then
        CascadeStyleLookup(lStyledControl.StyleName);
    end;
  end;
  if AComponent.Children = nil then
    exit;

  // Check the children of this component for the style.
  for lChild in AComponent.Children do
    CascadeStyleLookup(AStyleLookup, lChild);

end;

function TCascadingStyleLookup.FindUltimateParentForm(AChild: TFMXObject)
  : TFMXObject;
begin
  Result := nil;
  if (AChild.Parent <> nil) and (NOT(AChild.Parent.InheritsFrom(TForm))) then
    Result := FindUltimateParentForm(AChild)
  else
    Result := AChild.Parent;
end;

end.

这允许为组件所在的整个表单自动搜索和更新任何嵌套的“stylelookup”属性。

我用一个额外的组件更新了我的原始示例,该组件MyTextLabel2取决于MyTextLabel.

因此,现在设置BaseStyleLabel为 *BaseStyle1、23* 中的任何一个都将级联到 MyTextLabel。当 MyTextLabel 更改其样式时,这将级联到 MyTextLabel2。因此,当 BaseStyleLabel 通过简单地调用更新时,所有三个标签都将显示“STYLE TWO” BaseStyleLabel.CascadeStyleLookup('BaseStyle2')

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants,
  FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
  FMX.CascadingStyleLookup
  ;

type
  TForm1 = class(TForm)
    MyTextLabel: TLabel;
    StyleBook1: TStyleBook;
    BaseStyleLabel: TLabel;
    Button1: TButton;
    MyTextLabel2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Set up BaseStyleLabel as a Style Source
  BaseStyleLabel.StyleName := 'BaseStyle';
  // Set its Style to a Resources Style "STYLE ONE"
  BaseStyleLabel.StyleLookup := 'BaseStyle1';

  // Point MyTextLabel to whatever "BaseStyleLabel" is styled as...
  MyTextLabel.StyleName := 'MyTextBaseStyle';
  MyTextLabel.StyleLookup := 'BaseStyle'; // also says "STYLE ONE"

  // New component MyTextLabel2 points to whatever "MyTextLabel" is styled as...
  MyTextLabel2.StyleLookup := 'MyTextBaseStyle'; // also says "STYLE ONE",
                                                 // (from MyTextLabel)

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // Change BaseStyle Label to "STYLE TWO" (now cascades to all)
  BaseStyleLabel.CascadeStyleLookup('BaseStyle2');

end;
于 2018-03-29T06:24:58.497 回答