Bagikan melalui


Meneruskan Parameter Efek sebagai Properti Terlampir

Properti terlampir dapat digunakan untuk menentukan parameter efek yang merespons perubahan properti runtime. Artikel ini menunjukkan penggunaan properti terlampir untuk meneruskan parameter ke efek, dan mengubah parameter saat runtime.

Proses untuk membuat parameter efek yang merespons perubahan properti runtime adalah sebagai berikut:

  1. Buat static kelas yang berisi properti terlampir untuk setiap parameter yang akan diteruskan ke efek.
  2. Tambahkan properti terlampir tambahan ke kelas yang akan digunakan untuk mengontrol penambahan atau penghapusan efek ke kontrol tempat kelas akan dilampirkan. Pastikan bahwa properti terlampir ini mendaftarkan propertyChanged delegasi yang akan dijalankan ketika nilai properti berubah.
  3. Buat static getter dan setter untuk setiap properti terlampir.
  4. Terapkan logika di propertyChanged delegasi untuk menambahkan dan menghapus efeknya.
  5. Terapkan kelas berlapis di dalam static kelas, dinamai sesuai efek, yang mensubkelas RoutingEffect kelas. Untuk konstruktor, panggil konstruktor kelas dasar, meneruskan perangkaian nama grup resolusi, dan ID unik yang ditentukan pada setiap kelas efek khusus platform.

Parameter kemudian dapat diteruskan ke efek dengan menambahkan properti terlampir, dan nilai properti, ke kontrol yang sesuai. Selain itu, parameter dapat diubah pada runtime dengan menentukan nilai properti terlampir baru.

Catatan

Properti terlampir adalah jenis properti khusus yang dapat diikat, didefinisikan dalam satu kelas tetapi dilampirkan ke objek lain, dan dapat dikenali dalam XAML sebagai atribut yang berisi kelas dan nama properti yang dipisahkan oleh titik. Untuk informasi selengkapnya, lihat Properti Terlampir.

Aplikasi sampel menunjukkan ShadowEffect yang menambahkan bayangan ke teks yang Label ditampilkan oleh kontrol. Selain itu, warna bayangan dapat diubah pada runtime. Diagram berikut mengilustrasikan tanggung jawab setiap proyek dalam aplikasi sampel, bersama dengan hubungan di antara mereka:

Tanggung Jawab Proyek Efek Bayangan

Label Kontrol pada HomePage disesuaikan oleh LabelShadowEffect di setiap proyek khusus platform. Parameter diteruskan ke masing-masing LabelShadowEffect melalui properti terlampir di ShadowEffect kelas . Setiap LabelShadowEffect kelas berasal dari PlatformEffect kelas untuk setiap platform. Ini menghasilkan bayangan yang ditambahkan ke teks yang ditampilkan oleh Label kontrol, seperti yang ditunjukkan pada cuplikan layar berikut:

Efek Bayangan pada setiap Platform

Membuat Parameter Efek

Kelas static harus dibuat untuk mewakili parameter efek, seperti yang ditunjukkan dalam contoh kode berikut:

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")
    {
    }
  }
}

ShadowEffect berisi lima properti terlampir, dengan static getter dan setter untuk setiap properti terlampir. Empat properti ini mewakili parameter yang akan diteruskan ke setiap platform khusus LabelShadowEffect. Kelas juga ShadowEffect mendefinisikan HasShadow properti terlampir yang digunakan untuk mengontrol penambahan atau penghapusan efek ke kontrol tempat ShadowEffect kelas dilampirkan. Properti terlampir ini mendaftarkan OnHasShadowChanged metode yang akan dijalankan ketika nilai properti berubah. Metode ini menambahkan atau menghapus efek berdasarkan nilai HasShadow properti terlampir.

Kelas berlapis LabelShadowEffect , yang mensubkelas RoutingEffect kelas, mendukung penambahan dan penghapusan efek. Kelas ini RoutingEffect mewakili efek independen platform yang membungkus efek dalam yang biasanya khusus platform. Ini menyederhanakan proses penghapusan efek, karena tidak ada akses waktu kompilasi ke informasi jenis untuk efek khusus platform. LabelShadowEffect Konstruktor memanggil konstruktor kelas dasar, meneruskan parameter yang terdiri dari perangkaian nama grup resolusi, dan ID unik yang ditentukan pada setiap kelas efek khusus platform. Ini memungkinkan penambahan dan penghapusan efek dalam OnHasShadowChanged metode , sebagai berikut:

  • Penambahan efek – instans LabelShadowEffect baru ditambahkan ke koleksi kontrol Effects . Ini menggantikan menggunakan Effect.Resolve metode untuk menambahkan efek.
  • Penghapusan efek – instans LabelShadowEffect pertama dalam koleksi kontrol Effects diambil dan dihapus.

Mengkonsumsi Efek

Setiap platform khusus LabelShadowEffect dapat digunakan dengan menambahkan properti terlampir ke kontrol, seperti yang Label ditunjukkan dalam contoh kode XAML berikut:

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

Yang setara Label dalam C# ditunjukkan dalam contoh kode berikut:

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 Mengatur properti terlampir untuk true menjalankan ShadowEffect.OnHasShadowChanged metode yang menambahkan atau menghapus ke LabelShadowEffectLabel kontrol. Dalam kedua contoh kode, ShadowEffect.Color properti terlampir menyediakan nilai warna khusus platform. Untuk informasi selengkapnya, lihat Kelas Perangkat.

Selain itu, memungkinkan Button warna bayangan diubah pada runtime. Saat diklik Button , kode berikut mengubah warna bayangan dengan mengatur ShadowEffect.Color properti terlampir:

ShadowEffect.SetColor (label, Color.Teal);

Mengkonsumsi Efek dengan Gaya

Efek yang dapat dikonsumsi dengan menambahkan properti terlampir ke kontrol juga dapat dikonsumsi oleh gaya. Contoh kode XAML berikut menunjukkan gaya eksplisit untuk efek bayangan, yang dapat diterapkan ke Label kontrol:

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

Style dapat diterapkan ke a Label dengan mengatur propertinya Style ke Style instans menggunakan StaticResource ekstensi markup, seperti yang ditunjukkan dalam contoh kode berikut:

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

Untuk informasi selengkapnya tentang gaya, lihat Gaya.

Membuat Efek pada setiap Platform

Bagian berikut membahas implementasi LabelShadowEffect kelas khusus platform.

Proyek iOS

Contoh kode berikut menunjukkan LabelShadowEffect implementasi untuk proyek 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));
        }
    }

Metode ini OnAttached memanggil metode yang mengambil nilai properti terlampir menggunakan getter ShadowEffect , dan yang mengatur Control.Layer properti ke nilai properti untuk membuat bayangan. Fungsionalitas ini dibungkus dalam try/catch blok jika kontrol yang dilampirkan efek tidak memiliki Control.Layer properti . Tidak ada implementasi yang disediakan oleh OnDetached metode karena tidak diperlukan pembersihan.

Menanggapi Perubahan Properti

Jika salah ShadowEffect satu nilai properti terlampir berubah pada runtime, efek perlu merespons dengan menampilkan perubahan. Versi OnElementPropertyChanged metode yang ditimpa, di kelas efek khusus platform, adalah tempat untuk menanggapi perubahan properti yang dapat diikat, seperti yang ditunjukkan dalam contoh kode berikut:

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

Metode ini OnElementPropertyChanged memperbarui radius, warna, atau offset bayangan, asalkan nilai properti terlampir yang sesuai ShadowEffect telah berubah. Pemeriksaan properti yang diubah harus selalu dilakukan, karena penimpaan ini dapat dipanggil berkali-kali.

Proyek Android

Contoh kode berikut menunjukkan LabelShadowEffect implementasi untuk proyek 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);
        }
    }

Metode ini OnAttached memanggil metode yang mengambil nilai properti terlampir menggunakan getter ShadowEffect , dan memanggil metode yang memanggil TextView.SetShadowLayer metode untuk membuat bayangan menggunakan nilai properti. Fungsionalitas ini dibungkus dalam try/catch blok jika kontrol yang dilampirkan efek tidak memiliki Control.Layer properti . Tidak ada implementasi yang disediakan oleh OnDetached metode karena tidak diperlukan pembersihan.

Menanggapi Perubahan Properti

Jika salah ShadowEffect satu nilai properti terlampir berubah pada runtime, efek perlu merespons dengan menampilkan perubahan. Versi OnElementPropertyChanged metode yang ditimpa, di kelas efek khusus platform, adalah tempat untuk menanggapi perubahan properti yang dapat diikat, seperti yang ditunjukkan dalam contoh kode berikut:

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

Metode ini OnElementPropertyChanged memperbarui radius, warna, atau offset bayangan, asalkan nilai properti terlampir yang sesuai ShadowEffect telah berubah. Pemeriksaan properti yang diubah harus selalu dilakukan, karena penimpaan ini dapat dipanggil berkali-kali.

Proyek Platform Windows Universal

Contoh kode berikut menunjukkan LabelShadowEffect implementasi untuk proyek Platform Windows Universal (UWP):

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

Platform Windows Universal tidak memberikan efek bayangan, sehingga LabelShadowEffect implementasi pada kedua platform mensimulasikan satu dengan menambahkan offset Label kedua di belakang primer Label. Metode OnAttached ini membuat baru Label dan mengatur beberapa properti tata letak pada Label. Kemudian memanggil metode yang mengambil nilai properti terlampir menggunakan getter ShadowEffect , dan membuat bayangan dengan mengatur TextColorproperti , , TranslationXdan TranslationY untuk mengontrol warna dan lokasi Label. shadowLabel kemudian dimasukkan offset di belakang primer Label. Fungsionalitas ini dibungkus dalam try/catch blok jika kontrol yang dilampirkan efek tidak memiliki Control.Layer properti . Tidak ada implementasi yang disediakan oleh OnDetached metode karena tidak diperlukan pembersihan.

Menanggapi Perubahan Properti

Jika salah ShadowEffect satu nilai properti terlampir berubah pada runtime, efek perlu merespons dengan menampilkan perubahan. Versi OnElementPropertyChanged metode yang ditimpa, di kelas efek khusus platform, adalah tempat untuk menanggapi perubahan properti yang dapat diikat, seperti yang ditunjukkan dalam contoh kode berikut:

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

Metode memperbarui OnElementPropertyChanged warna atau offset bayangan, asalkan nilai properti terlampir yang sesuai ShadowEffect telah berubah. Pemeriksaan properti yang diubah harus selalu dilakukan, karena penimpaan ini dapat dipanggil berkali-kali.

Ringkasan

Artikel ini telah menunjukkan menggunakan properti terlampir untuk meneruskan parameter ke efek, dan mengubah parameter saat runtime. Properti terlampir dapat digunakan untuk menentukan parameter efek yang merespons perubahan properti runtime.