Partilhar via


Passando parâmetros de efeito como propriedades de Common Language Runtime

Propriedades de CLR (Common Language Runtime) podem ser usadas para definir parâmetros de efeito que não respondem a alterações de propriedade de tempo de execução. Este artigo demonstra como usar propriedades de CLR para passar parâmetros para um efeito.

O processo para criar parâmetros de efeito que não respondem a alterações de propriedade de runtime é o seguinte:

  1. Criar uma public que cria subclasses da classe RoutingEffect. A classe RoutingEffect representa um efeito independente de plataforma que encapsula um efeito interno, que é geralmente é específico da plataforma.
  2. Crie um construtor que chama o construtor da classe base, passando uma concatenação do nome do grupo de resolução e a ID exclusiva que foi especificada em cada classe de efeito específica da plataforma.
  3. Adicione propriedades à classe para cada parâmetro a ser passado para o efeito.

Em seguida, os parâmetros podem ser passados para o efeito especificando valores para cada propriedade ao instanciar o efeito.

O aplicativo de exemplo demonstra um ShadowEffect que adiciona uma sombra ao texto exibido por um controle Label. O seguinte diagrama ilustra as responsabilidades de cada projeto no aplicativo de exemplo, bem como as relações entre elas:

Responsabilidades do projeto de efeito de sombra

Um controle Label no HomePage é personalizado pelo LabelShadowEffect em cada projeto específico da plataforma. Os parâmetros são passados para cada LabelShadowEffect por meio das propriedades na classe ShadowEffect. Cada classe LabelShadowEffect é derivada da classe PlatformEffect de cada plataforma. Isso faz com que uma sombra seja adicionada ao texto exibido pelo controle Label, conforme mostrado nas capturas de tela seguir:

Efeito de sombra em cada plataforma

Criando parâmetros de efeito

Uma classe public que cria subclasses da classe RoutingEffect deve ser criada para representar os parâmetros em vigor, conforme demonstrado no exemplo de código a seguir:

public class ShadowEffect : RoutingEffect
{
  public float Radius { get; set; }

  public Color Color { get; set; }

  public float DistanceX { get; set; }

  public float DistanceY { get; set; }

  public ShadowEffect () : base ("MyCompany.LabelShadowEffect")
  {            
  }
}

O ShadowEffect contém quatro propriedades que representam os parâmetros a serem passados para cada LabelShadowEffect específico da plataforma. O construtor de classe chama o construtor da classe base, passando um parâmetro composto por uma concatenação do nome do grupo de resolução e pela ID exclusiva que foi especificada em cada classe de efeito específica da plataforma. Portanto, uma nova instância de MyCompany.LabelShadowEffect será adicionada à coleção Effects do controle quando um ShadowEffect for instanciado.

Consumindo o efeito

O exemplo de código XAML abaixo mostra um controle Label ao qual o ShadowEffect está anexado:

<Label Text="Label Shadow Effect" ...>
  <Label.Effects>
    <local:ShadowEffect Radius="5" DistanceX="5" DistanceY="5">
      <local:ShadowEffect.Color>
        <OnPlatform x:TypeArguments="Color">
            <On Platform="iOS" Value="Black" />
            <On Platform="Android" Value="White" />
            <On Platform="UWP" Value="Red" />
        </OnPlatform>
      </local:ShadowEffect.Color>
    </local:ShadowEffect>
  </Label.Effects>
</Label>

O Label equivalente em C# é mostrado no exemplo de código a seguir:

var label = new Label {
  Text = "Label Shadow Effect",
  ...
};

Color color = Color.Default;
switch (Device.RuntimePlatform)
{
    case Device.iOS:
        color = Color.Black;
        break;
    case Device.Android:
        color = Color.White;
        break;
    case Device.UWP:
        color = Color.Red;
        break;
}

label.Effects.Add (new ShadowEffect {
  Radius = 5,
  Color = color,
  DistanceX = 5,
  DistanceY = 5
});

Nos dois exemplos de código, uma instância da classe ShadowEffect é criada, com valores especificados para cada propriedade, antes de ser adicionada à coleção Effects do controle. Observe que a propriedade ShadowEffect.Color usa valores de cor específicos da plataforma. Para obter mais informações, confira Classe do dispositivo.

Criando o efeito em cada plataforma

As seções a seguir abordam a implementação da classe LabelShadowEffect específica da plataforma.

Projeto do iOS

O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do iOS:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
    public class LabelShadowEffect : PlatformEffect
    {
        protected override void OnAttached ()
        {
            try {
                var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
                if (effect != null) {
                    Control.Layer.ShadowRadius = effect.Radius;
                    Control.Layer.ShadowColor = effect.Color.ToCGColor ();
                    Control.Layer.ShadowOffset = new CGSize (effect.DistanceX, effect.DistanceY);
                    Control.Layer.ShadowOpacity = 1.0f;
                }
            } catch (Exception ex) {
                Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
            }
        }

        protected override void OnDetached ()
        {
        }
    }
}

O método OnAttached recupera a instância de ShadowEffect e define propriedades de Control.Layer como os valores de propriedade especificados para criar a sombra. Essa funcionalidade é encapsulada em um bloco try/catch caso o controle a que o efeito está anexado não tenha as propriedades de Control.Layer. Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.

Projeto do Android

O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto do Android:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
    public class LabelShadowEffect : PlatformEffect
    {
        protected override void OnAttached ()
        {
            try {
                var control = Control as Android.Widget.TextView;
                var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
                if (effect != null) {
                    float radius = effect.Radius;
                    float distanceX = effect.DistanceX;
                    float distanceY = effect.DistanceY;
                    Android.Graphics.Color color = effect.Color.ToAndroid ();
                    control.SetShadowLayer (radius, distanceX, distanceY, color);
                }
            } catch (Exception ex) {
                Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
            }
        }

        protected override void OnDetached ()
        {
        }
    }
}

O método OnAttached recupera a instância de ShadowEffect e chama o método TextView.SetShadowLayer para criar uma sombra usando os valores de propriedade especificados. Essa funcionalidade é encapsulada em um bloco try/catch caso o controle a que o efeito está anexado não tenha as propriedades de Control.Layer. Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.

Projeto da Plataforma Universal do Windows

O exemplo de código a seguir mostra a implementação de LabelShadowEffect para o projeto da UWP (Plataforma Universal do Windows):

[assembly: ResolutionGroupName ("Xamarin")]
[assembly: ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.UWP
{
    public class LabelShadowEffect : PlatformEffect
    {
        bool shadowAdded = false;

        protected override void OnAttached ()
        {
            try {
                if (!shadowAdded) {
                    var effect = (ShadowEffect)Element.Effects.FirstOrDefault (e => e is ShadowEffect);
                    if (effect != null) {
                        var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;
                        var shadowLabel = new Label ();
                        shadowLabel.Text = textBlock.Text;
                        shadowLabel.FontAttributes = FontAttributes.Bold;
                        shadowLabel.HorizontalOptions = LayoutOptions.Center;
                        shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;
                        shadowLabel.TextColor = effect.Color;
                        shadowLabel.TranslationX = effect.DistanceX;
                        shadowLabel.TranslationY = effect.DistanceY;

                        ((Grid)Element.Parent).Children.Insert (0, shadowLabel);
                        shadowAdded = true;
                    }
                }
            } catch (Exception ex) {
                Debug.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
            }
        }

        protected override void OnDetached ()
        {
        }
    }
}

A Plataforma Universal do Windows não fornece um efeito de sombra, de forma que a implementação de LabelShadowEffect nas duas plataformas simula o efeito adicionando um segundo deslocamento Label atrás do Label principal. O método OnAttached recupera a instância de ShadowEffect, cria o novo Label e define algumas propriedades de layout no Label. Depois, ele cria a sombra definindo as propriedades TextColor, TranslationX e TranslationY para controlar a cor e a localização do Label. Em seguida, o shadowLabel é inserido deslocado atrás do Label principal. Essa funcionalidade é encapsulada em um bloco try/catch caso o controle a que o efeito está anexado não tenha as propriedades de Control.Layer. Nenhuma implementação é fornecida pelo método OnDetached porque nenhuma limpeza é necessária.

Resumo

Este artigo demonstrou como usar propriedades de CLR para passar parâmetros para um efeito. Propriedades de CLR podem ser usadas para definir parâmetros de efeito que não respondem a alterações de propriedade de runtime.