Sdílet prostřednictvím


Předávání parametrů efektu jako připojených vlastností

Připojené vlastnosti lze použít k definování parametrů efektu, které reagují na změny vlastností modulu runtime. Tento článek ukazuje použití připojených vlastností k předání parametrů efektu a změně parametru za běhu.

Proces vytváření parametrů efektu, které reagují na změny vlastností modulu runtime, je následující:

  1. Vytvořte static třídu, která obsahuje připojenou vlastnost pro každý parametr, který se má předat efektu.
  2. Přidejte do třídy další připojenou vlastnost, která bude použita k řízení přidání nebo odebrání efektu do ovládacího prvku, ke kterému bude třída připojena. Zajistěte, aby tato připojená vlastnost registrovala delegáta propertyChanged , který se spustí při změně hodnoty vlastnosti.
  3. Vytvořte static getters a setter pro každou připojenou vlastnost.
  4. Implementujte v delegátu logiku propertyChanged pro přidání a odebrání efektu.
  5. Implementujte vnořenou třídu uvnitř static třídy pojmenovanou za efektem, která podtřídy RoutingEffect třídy. Pro konstruktor volejte konstruktor základní třídy, předejte zřetězení názvu skupiny překladu a jedinečné ID, které bylo zadáno v každé třídě efektu specifické pro platformu.

Parametry se pak dají předat do efektu přidáním připojených vlastností a hodnot vlastností do příslušného ovládacího prvku. Parametry lze navíc změnit za běhu zadáním nové připojené hodnoty vlastnosti.

Poznámka:

Připojená vlastnost je speciální typ bindable vlastnost, definovaná v jedné třídě, ale připojena k jiným objektům, a rozpoznatelná v XAML jako atributy, které obsahují třídu a název vlastnosti oddělené tečkou. Další informace naleznete v tématu Připojené vlastnosti.

Ukázková aplikace ukazuje ShadowEffect , že přidá stín k textu zobrazenému ovládacím Label prvku. Kromě toho je možné změnit barvu stínu za běhu. Následující diagram znázorňuje zodpovědnosti jednotlivých projektů v ukázkové aplikaci spolu s relacemi mezi nimi:

Odpovědnosti projektu stínového efektu

Label Ovládací prvek na dané HomePage platformě je přizpůsobený LabelShadowEffect v každém projektu specifickém pro platformu. Parametry jsou předány každému LabelShadowEffect ShadowEffect prostřednictvím připojených vlastností ve třídě. Každá LabelShadowEffect třída je odvozena od PlatformEffect třídy pro každou platformu. Výsledkem je přidání stínu do textu zobrazeného ovládacím Label prvku, jak je znázorněno na následujících snímcích obrazovky:

Stínový efekt na jednotlivých platformách

Vytvoření parametrů efektu

Vytvoří static se třída, která bude představovat parametry efektu, jak je znázorněno v následujícím příkladu kódu:

public static class ShadowEffect
{
  public static readonly BindableProperty HasShadowProperty =
    BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false, propertyChanged: OnHasShadowChanged);
  public static readonly BindableProperty ColorProperty =
    BindableProperty.CreateAttached ("Color", typeof(Color), typeof(ShadowEffect), Color.Default);
  public static readonly BindableProperty RadiusProperty =
    BindableProperty.CreateAttached ("Radius", typeof(double), typeof(ShadowEffect), 1.0);
  public static readonly BindableProperty DistanceXProperty =
    BindableProperty.CreateAttached ("DistanceX", typeof(double), typeof(ShadowEffect), 0.0);
  public static readonly BindableProperty DistanceYProperty =
    BindableProperty.CreateAttached ("DistanceY", typeof(double), typeof(ShadowEffect), 0.0);

  public static bool GetHasShadow (BindableObject view)
  {
    return (bool)view.GetValue (HasShadowProperty);
  }

  public static void SetHasShadow (BindableObject view, bool value)
  {
    view.SetValue (HasShadowProperty, value);
  }
  ...

  static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue)
  {
    var view = bindable as View;
    if (view == null) {
      return;
    }

    bool hasShadow = (bool)newValue;
    if (hasShadow) {
      view.Effects.Add (new LabelShadowEffect ());
    } else {
      var toRemove = view.Effects.FirstOrDefault (e => e is LabelShadowEffect);
      if (toRemove != null) {
        view.Effects.Remove (toRemove);
      }
    }
  }

  class LabelShadowEffect : RoutingEffect
  {
    public LabelShadowEffect () : base ("MyCompany.LabelShadowEffect")
    {
    }
  }
}

Obsahuje ShadowEffect pět připojených vlastností s static getters a setter pro každou připojenou vlastnost. Čtyři z těchto vlastností představují parametry, které se mají předat jednotlivým platformám LabelShadowEffect. Třída ShadowEffect také definuje připojenou HasShadow vlastnost, která se používá k řízení přidání nebo odebrání efektu k ovládacímu prvku, ke kterému ShadowEffect je třída připojena. Tato připojená vlastnost registruje metodu OnHasShadowChanged , která se spustí při změně hodnoty vlastnosti. Tato metoda přidá nebo odebere účinek na základě hodnoty HasShadow připojené vlastnosti.

Vnořená LabelShadowEffect třída, která podtřídy RoutingEffect třídy, podporuje přidání a odebrání efektu. Třída RoutingEffect představuje efekt nezávislý na platformě, který zabalí vnitřní efekt, který je obvykle specifický pro platformu. To zjednodušuje proces odebrání efektu, protože neexistuje žádný přístup k informacím o typu pro efekt specifický pro platformu. Konstruktor LabelShadowEffect volá konstruktor základní třídy, který předává parametr skládající se zřetězení názvu skupiny překladu a jedinečné ID zadané pro každou třídu efektu specifické pro platformu. To umožňuje přidání a odebrání efektu OnHasShadowChanged v metodě následujícím způsobem:

  • Přidání efektu – nová instance objektu LabelShadowEffect je přidána do kolekce ovládacího prvku Effects . Tím se nahradí použitím Effect.Resolve metody pro přidání efektu.
  • Odebrání efektu LabelShadowEffect – první instance kolekce ovládacího prvku Effects se načte a odebere.

Využívání efektu

Jednotlivé platformy LabelShadowEffect je možné využívat přidáním připojených vlastností do Label ovládacího prvku, jak je znázorněno v následujícím příkladu kódu XAML:

<Label Text="Label Shadow Effect" ...
       local:ShadowEffect.HasShadow="true" local:ShadowEffect.Radius="5"
       local:ShadowEffect.DistanceX="5" local:ShadowEffect.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>
</Label>

Ekvivalent Label v jazyce C# je znázorněn v následujícím příkladu kódu:

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;
}

ShadowEffect.SetHasShadow (label, true);
ShadowEffect.SetRadius (label, 5);
ShadowEffect.SetDistanceX (label, 5);
ShadowEffect.SetDistanceY (label, 5);
ShadowEffect.SetColor (label, color));

ShadowEffect.HasShadow Nastavením připojené vlastnosti spustíte true metoduShadowEffect.OnHasShadowChanged, která přidá nebo odebere LabelShadowEffect ovládací prvekLabel. V obou příkladech kódu poskytuje připojená ShadowEffect.Color vlastnost hodnoty barev specifické pro platformu. Další informace naleznete v tématu Třída zařízení.

Kromě toho Button umožňuje změnit barvu stínu za běhu. Button Po kliknutí změní následující kód barvu stínu ShadowEffect.Color nastavením připojené vlastnosti:

ShadowEffect.SetColor (label, Color.Teal);

Využívání efektu se stylem

Efekty, které lze využívat přidáním připojených vlastností do ovládacího prvku, mohou být také využity stylem. Následující příklad kódu XAML ukazuje explicitní styl stínového efektu, který lze použít u Label ovládacích prvků:

<Style x:Key="ShadowEffectStyle" TargetType="Label">
  <Style.Setters>
    <Setter Property="local:ShadowEffect.HasShadow" Value="True" />
    <Setter Property="local:ShadowEffect.Radius" Value="5" />
    <Setter Property="local:ShadowEffect.DistanceX" Value="5" />
    <Setter Property="local:ShadowEffect.DistanceY" Value="5" />
  </Style.Setters>
</Style>

Lze Style použít na objekt Label nastavením jeho Style vlastnosti na Style instanci pomocí StaticResource rozšíření značek, jak je znázorněno v následujícím příkladu kódu:

<Label Text="Label Shadow Effect" ... Style="{StaticResource ShadowEffectStyle}" />

Další informace o stylech naleznete v tématu Styly.

Vytvoření efektu na jednotlivých platformách

Následující části diskutují o implementaci třídy specifické pro danou platformu LabelShadowEffect .

Projekt pro iOS

Následující příklad kódu ukazuje implementaci LabelShadowEffect projektu iOS:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.iOS
{
    public class LabelShadowEffect : PlatformEffect
    {
        protected override void OnAttached ()
        {
            try {
                UpdateRadius ();
                UpdateColor ();
                UpdateOffset ();
                Control.Layer.ShadowOpacity = 1.0f;
            } catch (Exception ex) {
                Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
            }
        }

        protected override void OnDetached ()
        {
        }
        ...

        void UpdateRadius ()
        {
            Control.Layer.ShadowRadius = (nfloat)ShadowEffect.GetRadius (Element);
        }

        void UpdateColor ()
        {
            Control.Layer.ShadowColor = ShadowEffect.GetColor (Element).ToCGColor ();
        }

        void UpdateOffset ()
        {
            Control.Layer.ShadowOffset = new CGSize (
                (double)ShadowEffect.GetDistanceX (Element),
                (double)ShadowEffect.GetDistanceY (Element));
        }
    }

Metoda OnAttached volá metody, které načítají připojené hodnoty vlastností pomocí ShadowEffect getters a které nastaví Control.Layer vlastnosti na hodnoty vlastnosti k vytvoření stínu. Tato funkce je zabalena do try/catch bloku v případě, že ovládací prvek, ke kterému je efekt připojen, nemá Control.Layer vlastnosti. Metoda neposkytuje OnDetached žádnou implementaci, protože není nutné vyčistit.

Reakce na změny vlastností

Pokud se některé z připojených ShadowEffect hodnot vlastností změní za běhu, musí efekt reagovat zobrazením změn. Přepsáná verze metody, která je ve třídě efektu OnElementPropertyChanged specifická pro platformu, je místo, kde můžete reagovat na změny vazebných vlastností, jak je znázorněno v následujícím příkladu kódu:

public class LabelShadowEffect : PlatformEffect
{
  ...
  protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
  {
    if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
      UpdateRadius ();
    } else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
      UpdateColor ();
    } else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
               args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
      UpdateOffset ();
    }
  }
  ...
}

Metoda OnElementPropertyChanged aktualizuje poloměr, barvu nebo posun stínu za předpokladu, že se změnila příslušná ShadowEffect hodnota připojené vlastnosti. Kontrola změněné vlastnosti by měla být vždy provedena, protože toto přepsání lze volat mnohokrát.

Android Project

Následující příklad kódu ukazuje implementaci LabelShadowEffect projektu Android:

[assembly:ResolutionGroupName ("MyCompany")]
[assembly:ExportEffect (typeof(LabelShadowEffect), "LabelShadowEffect")]
namespace EffectsDemo.Droid
{
    public class LabelShadowEffect : PlatformEffect
    {
        Android.Widget.TextView control;
        Android.Graphics.Color color;
        float radius, distanceX, distanceY;

        protected override void OnAttached ()
        {
            try {
                control = Control as Android.Widget.TextView;
                UpdateRadius ();
                UpdateColor ();
                UpdateOffset ();
                UpdateControl ();
            } catch (Exception ex) {
                Console.WriteLine ("Cannot set property on attached control. Error: ", ex.Message);
            }
        }

        protected override void OnDetached ()
        {
        }
        ...

        void UpdateControl ()
        {
            if (control != null) {
                control.SetShadowLayer (radius, distanceX, distanceY, color);
            }
        }

        void UpdateRadius ()
        {
            radius = (float)ShadowEffect.GetRadius (Element);
        }

        void UpdateColor ()
        {
            color = ShadowEffect.GetColor (Element).ToAndroid ();
        }

        void UpdateOffset ()
        {
            distanceX = (float)ShadowEffect.GetDistanceX (Element);
            distanceY = (float)ShadowEffect.GetDistanceY (Element);
        }
    }

Metoda OnAttached volá metody, které načítají připojené hodnoty vlastností pomocí ShadowEffect getters, a volá metodu, která volá metodu TextView.SetShadowLayer k vytvoření stínu pomocí hodnot vlastností. Tato funkce je zabalena do try/catch bloku v případě, že ovládací prvek, ke kterému je efekt připojen, nemá Control.Layer vlastnosti. Metoda neposkytuje OnDetached žádnou implementaci, protože není nutné vyčistit.

Reakce na změny vlastností

Pokud se některé z připojených ShadowEffect hodnot vlastností změní za běhu, musí efekt reagovat zobrazením změn. Přepsáná verze metody, která je ve třídě efektu OnElementPropertyChanged specifická pro platformu, je místo, kde můžete reagovat na změny vazebných vlastností, jak je znázorněno v následujícím příkladu kódu:

public class LabelShadowEffect : PlatformEffect
{
  ...
  protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
  {
    if (args.PropertyName == ShadowEffect.RadiusProperty.PropertyName) {
      UpdateRadius ();
      UpdateControl ();
    } else if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
      UpdateColor ();
      UpdateControl ();
    } else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
               args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
      UpdateOffset ();
      UpdateControl ();
    }
  }
  ...
}

Metoda OnElementPropertyChanged aktualizuje poloměr, barvu nebo posun stínu za předpokladu, že se změnila příslušná ShadowEffect hodnota připojené vlastnosti. Kontrola změněné vlastnosti by měla být vždy provedena, protože toto přepsání lze volat mnohokrát.

Univerzální platforma Windows Project

Následující příklad kódu ukazuje implementaci LabelShadowEffect projektu Univerzální platforma Windows (UPW):

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

        protected override void OnAttached ()
        {
            try {
                if (!shadowAdded) {
                    var textBlock = Control as Windows.UI.Xaml.Controls.TextBlock;

                    shadowLabel = new Label ();
                    shadowLabel.Text = textBlock.Text;
                    shadowLabel.FontAttributes = FontAttributes.Bold;
                    shadowLabel.HorizontalOptions = LayoutOptions.Center;
                    shadowLabel.VerticalOptions = LayoutOptions.CenterAndExpand;

                    UpdateColor ();
                    UpdateOffset ();

                    ((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 ()
        {
        }
        ...

        void UpdateColor ()
        {
            shadowLabel.TextColor = ShadowEffect.GetColor (Element);
        }

        void UpdateOffset ()
        {
            shadowLabel.TranslationX = ShadowEffect.GetDistanceX (Element);
            shadowLabel.TranslationY = ShadowEffect.GetDistanceY (Element);
        }
    }
}

Univerzální platforma Windows neposkytuje stínový efekt, a proto LabelShadowEffect implementace na obou platformách simuluje jeden přidáním druhého posunu Label za primární Label. Metoda OnAttached vytvoří novou Label a nastaví některé vlastnosti rozložení v objektu Label. Potom volá metody, které načítají připojené hodnoty vlastností pomocí ShadowEffect getters, a vytvoří stín nastavením TextColor, TranslationXa TranslationY vlastnosti pro řízení barvy a umístění Label. Potom shadowLabel se vloží posun za primární Label. Tato funkce je zabalena do try/catch bloku v případě, že ovládací prvek, ke kterému je efekt připojen, nemá Control.Layer vlastnosti. Metoda neposkytuje OnDetached žádnou implementaci, protože není nutné vyčistit.

Reakce na změny vlastností

Pokud se některé z připojených ShadowEffect hodnot vlastností změní za běhu, musí efekt reagovat zobrazením změn. Přepsáná verze metody, která je ve třídě efektu OnElementPropertyChanged specifická pro platformu, je místo, kde můžete reagovat na změny vazebných vlastností, jak je znázorněno v následujícím příkladu kódu:

public class LabelShadowEffect : PlatformEffect
{
  ...
  protected override void OnElementPropertyChanged (PropertyChangedEventArgs args)
  {
    if (args.PropertyName == ShadowEffect.ColorProperty.PropertyName) {
      UpdateColor ();
    } else if (args.PropertyName == ShadowEffect.DistanceXProperty.PropertyName ||
                      args.PropertyName == ShadowEffect.DistanceYProperty.PropertyName) {
      UpdateOffset ();
    }
  }
  ...
}

Metoda OnElementPropertyChanged aktualizuje barvu nebo posun stínu za předpokladu, že se změnila příslušná ShadowEffect hodnota připojené vlastnosti. Kontrola změněné vlastnosti by měla být vždy provedena, protože toto přepsání lze volat mnohokrát.

Shrnutí

Tento článek ukázal použití připojených vlastností k předání parametrů efektu a změně parametru za běhu. Připojené vlastnosti lze použít k definování parametrů efektu, které reagují na změny vlastností modulu runtime.