Bir ListView’i Özelleştirme

Xamarin.Forms ListView, veri koleksiyonunu dikey liste olarak görüntüleyen bir görünümdür. Bu makalede, platforma özgü liste denetimlerini ve yerel hücre düzenlerini kapsülleyen ve yerel liste denetimi performansı üzerinde daha fazla denetim sağlayan bir özel işleyicinin nasıl oluşturulacağı gösterilmektedir.

Her Xamarin.Forms görünümde, yerel denetimin bir örneğini oluşturan her platform için eşlik eden bir işleyici vardır. bir ListView uygulama tarafından Xamarin.Forms işlendiğinde, iOS'ta ListViewRenderer sınıfın örneği oluşturulur ve bu da yerel UITableView bir denetimin örneğini oluşturur. Android platformunda ListViewRenderer , sınıfı yerel ListView bir denetim örneği oluşturur. Evrensel Windows Platformu (UWP) sınıfı ListViewRenderer yerel ListView bir denetim örneği oluşturur. Eşlenmeyi denetleen Xamarin.Forms işleyici ve yerel denetim sınıfları hakkında daha fazla bilgi için bkz . oluşturucu Temel Sınıfları ve Yerel Denetimler.

Aşağıdaki diyagramda denetim ile bunu uygulayan ilgili yerel denetimler arasındaki ListView ilişki gösterilmektedir:

ListView Denetimi ile Yerel Denetimleri Uygulama Arasındaki İlişki

İşleme işlemi, her platformda bir için özel işleyici oluşturarak platforma özgü özelleştirmeler uygulamak için ListView kullanılabilir. Bunu yapma işlemi aşağıdaki gibidir:

  1. Özel denetim Xamarin.Forms oluşturma.
  2. 'den Xamarin.Formsözel denetimi kullanma.
  3. Her platformda denetim için özel işleyici oluşturun .

Artık platforma özgü liste denetimlerinden ve yerel hücre düzenlerinden yararlanan bir NativeListView işleyici uygulamak için her öğe sırayla ele alınacaktır. Bu senaryo, yeniden kullanılabilecek liste ve hücre kodu içeren mevcut bir yerel uygulamayı taşıma sırasında kullanışlıdır. Ayrıca, veri sanallaştırma gibi performansı etkileyebilecek liste denetimi özelliklerinin ayrıntılı olarak özelleştirilmesini sağlar.

Özel ListView Denetimi Oluşturma

Aşağıdaki kod örneğinde gösterildiği gibi sınıfın alt sınıfı ListView oluşturularak özel ListView bir denetim oluşturulabilir:

public class NativeListView : ListView
{
  public static readonly BindableProperty ItemsProperty =
    BindableProperty.Create ("Items", typeof(IEnumerable<DataSource>), typeof(NativeListView), new List<DataSource> ());

  public IEnumerable<DataSource> Items {
    get { return (IEnumerable<DataSource>)GetValue (ItemsProperty); }
    set { SetValue (ItemsProperty, value); }
  }

  public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;

  public void NotifyItemSelected (object item)
  {
    if (ItemSelected != null) {
      ItemSelected (this, new SelectedItemChangedEventArgs (item));
    }
  }
}

, NativeListView .NET Standard kitaplık projesinde oluşturulur ve özel denetim için API'yi tanımlar. Bu denetim, verilerle doldurma ListView için kullanılan ve görüntüleme amacıyla bağlanabilen bir Items özelliği kullanıma sunar. Ayrıca platforma özgü yerel ItemSelected liste denetiminde bir öğe seçildiğinde tetiklenecek bir olayı da kullanıma sunar. Veri bağlama hakkında daha fazla bilgi için bkz . Veri Bağlama Temelleri.

Özel Denetimi Kullanma

Özel NativeListView denetime konumu için bir ad alanı bildirilerek ve denetimdeki ad alanı ön eki kullanılarak .NET Standart kitaplık projesindeki Xaml'de başvurulabilir. Aşağıdaki kod örneği, özel denetimin NativeListView bir XAML sayfası tarafından nasıl tüketilebileceğini gösterir:

<ContentPage ...
    xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
    ...>
    ...
    <ContentPage.Content>
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <RowDefinition Height="*" />
            </Grid.RowDefinitions>
          <Label Text="{x:Static local:App.Description}" HorizontalTextAlignment="Center" />
            <local:NativeListView Grid.Row="1" x:Name="nativeListView" ItemSelected="OnItemSelected" VerticalOptions="FillAndExpand" />
          </Grid>
      </ContentPage.Content>
</ContentPage>

Ad local alanı ön eki herhangi bir adla adlandırılabilir. Ancak ve clr-namespace assembly değerleri özel denetimin ayrıntılarıyla eşleşmelidir. Ad alanı bildirildikten sonra, özel denetime başvurmak için ön ek kullanılır.

Aşağıdaki kod örneği, özel denetimin NativeListView bir C# sayfası tarafından nasıl kullanılıp kullanılamayabileceğini gösterir:

public class MainPageCS : ContentPage
{
    NativeListView nativeListView;

    public MainPageCS()
    {
        nativeListView = new NativeListView
        {
            Items = DataSource.GetList(),
            VerticalOptions = LayoutOptions.FillAndExpand
        };

        switch (Device.RuntimePlatform)
        {
            case Device.iOS:
                Padding = new Thickness(0, 20, 0, 0);
                break;
            case Device.Android:
            case Device.UWP:
                Padding = new Thickness(0);
                break;
        }

        Content = new Grid
        {
            RowDefinitions = {
                new RowDefinition { Height = GridLength.Auto },
                new RowDefinition { Height = new GridLength (1, GridUnitType.Star) }
            },
            Children = {
                new Label { Text = App.Description, HorizontalTextAlignment = TextAlignment.Center },
                nativeListView
            }
        };
        nativeListView.ItemSelected += OnItemSelected;
    }
    ...
}

Özel NativeListView denetim, özellik aracılığıyla doldurulan bir veri listesi görüntülemek için platforma Items özgü özel işleyicileri kullanır. Listedeki her satır üç veri öğesi içerir: ad, kategori ve görüntü dosya adı. Listedeki her satırın düzeni platforma özgü özel işleyici tarafından tanımlanır.

Not

NativeListView Özel denetim, kaydırma özelliğini içeren platforma özgü liste denetimleri kullanılarak işlenecek olduğundan, özel denetim gibi ScrollViewkaydırılabilir düzen denetimlerinde barındırılmamalıdır.

Artık platforma özgü liste denetimleri ve yerel hücre düzenleri oluşturmak için her uygulama projesine özel işleyici eklenebilir.

Her Platformda Özel oluşturucu oluşturma

Özel işleyici sınıfını oluşturma işlemi aşağıdaki gibidir:

  1. Özel denetimi işleyen sınıfının bir alt sınıfını ListViewRenderer oluşturun.
  2. OnElementChanged Özel denetimi işleyen yöntemini geçersiz kılın ve özelleştirmek için mantık yazın. Bu yöntem, karşılık gelen Xamarin.FormsListView oluşturulduğunda çağrılır.
  3. Özel denetimi işlemek için kullanılacağını belirtmek için özel işleyici sınıfına Xamarin.Forms bir ExportRenderer öznitelik ekleyin. Bu öznitelik, özel işleyiciyi ile Xamarin.Formskaydetmek için kullanılır.

Not

Her platform projesinde özel işleyici sağlamak isteğe bağlıdır. Özel işleyici kaydedilmediyse, hücrenin temel sınıfı için varsayılan işleyici kullanılır.

Aşağıdaki diyagramda, örnek uygulamadaki her projenin sorumlulukları ve aralarındaki ilişkiler gösterilmektedir:

NativeListView Özel oluşturucu proje sorumlulukları

Özel NativeListView denetim, her platform için sınıfından ListViewRenderer türetilen platforma özgü işleyici sınıfları tarafından işlenir. Bu, her NativeListView özel denetimin aşağıdaki ekran görüntülerinde gösterildiği gibi platforma özgü liste denetimleri ve yerel hücre düzenleriyle işlenmesine neden olur:

Her Platformda NativeListView

ListViewRenderer sınıfı, ilgili yerel denetimi işlemek için özel denetim oluşturulduğunda çağrılan Xamarin.Forms yöntemini kullanıma sunarOnElementChanged. Bu yöntem ve NewElement özelliklerini içeren OldElement bir ElementChangedEventArgs parametre alır. Bu özellikler, işleyicinin eklendiği öğeyi ve Xamarin.Forms sırasıyla işleyicinin eklendiği öğeyi temsil Xamarin.Forms edilir. Örnek uygulamada özelliği OldElement olur null ve NewElement özelliği örneğe bir başvuru NativeListView içerir.

Her platforma özgü işleyici sınıfında yöntemin OnElementChanged geçersiz kılınmış bir sürümü, yerel denetim özelleştirmesinin gerçekleştirebileceğiniz yerdir. Platformda kullanılan yerel denetime yazılan başvuruya özelliği üzerinden Control erişilebilir. Ayrıca, işlenen denetime Xamarin.Forms bir başvuru özelliği aracılığıyla Element elde edilebilir.

Aşağıdaki kod örneğinde gösterildiği gibi yöntemindeki OnElementChanged olay işleyicilerine abone olurken dikkatli olunmalıdır:

protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
  base.OnElementChanged (e);

  if (e.OldElement != null) {
    // Unsubscribe from event handlers and cleanup any resources
  }

  if (e.NewElement != null) {
    // Configure the native control and subscribe to event handlers
  }
}

Yerel denetim yalnızca özel işleyici yeni Xamarin.Forms bir öğeye eklendiğinde yapılandırılmalıdır ve olay işleyicileri abone olmalıdır. Benzer şekilde, abone olunan tüm olay işleyicilerinin aboneliği yalnızca işleyicinin değişikliklere eklendiği öğe olduğunda aboneliği kaldırılmalıdır. Bu yaklaşımı benimsemek, bellek sızıntılarından muzdarip olmayan özel bir işleyici oluşturmaya yardımcı olur.

Yöntemin OnElementPropertyChanged geçersiz kılınmış sürümü, platforma özgü işleyici sınıflarında özel denetimdeki Xamarin.Forms bağlanabilir özellik değişikliklerine yanıt verilebilen yerdir. Bu geçersiz kılma birçok kez çağrılabildiği için, değiştirilen özellik için her zaman bir denetim yapılmalıdır.

Her özel işleyici sınıfı, işleyiciyi ile kaydeden bir ExportRenderer öznitelikle Xamarin.Formsdekore edilmiştir. özniteliği iki parametre alır: işlenen özel denetimin Xamarin.Forms tür adı ve özel işleyicinin tür adı. assembly özniteliğinin ön eki, özniteliğin tüm derleme için geçerli olduğunu belirtir.

Aşağıdaki bölümlerde platforma özgü özel işleyici sınıflarının uygulanması açıklanmıştır.

iOS'ta Özel oluşturucu oluşturma

Aşağıdaki kod örneği, iOS platformu için özel işleyiciyi gösterir:

[assembly: ExportRenderer (typeof(NativeListView), typeof(NativeiOSListViewRenderer))]
namespace CustomRenderer.iOS
{
    public class NativeiOSListViewRenderer : ListViewRenderer
    {
        protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.ListView> e)
        {
            base.OnElementChanged (e);

            if (e.OldElement != null) {
                // Unsubscribe
            }

            if (e.NewElement != null) {
                Control.Source = new NativeiOSListViewSource (e.NewElement as NativeListView);
            }
        }
    }
}

DenetimUITableView, özel işleyicinin yeni Xamarin.Forms bir öğeye NativeiOSListViewSource eklenmesi koşuluyla sınıfının bir örneği oluşturularak yapılandırılır. Bu sınıf, sınıfından UITableView ve GetCell yöntemlerini UITableViewSource geçersiz kılarak RowsInSection ve görüntülenecek veri listesini içeren bir Items özelliği kullanıma sunarak denetime veri sağlar. sınıfı, özel denetim tarafından NativeListView sağlanan olayı çağıran ItemSelected bir RowSelected yöntem geçersiz kılma da sağlar. Yöntem geçersiz kılmaları hakkında daha fazla bilgi için bkz . UITableViewSource Alt Sınıfı oluşturma. GetCell yöntemi, listedeki her satır için verilerle doldurulmuş bir UITableCellView döndürür ve aşağıdaki kod örneğinde gösterilir:

public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
  // request a recycled cell to save memory
  NativeiOSListViewCell cell = tableView.DequeueReusableCell (cellIdentifier) as NativeiOSListViewCell;

  // if there are no cells to reuse, create a new one
  if (cell == null) {
    cell = new NativeiOSListViewCell (cellIdentifier);
  }

  if (String.IsNullOrWhiteSpace (tableItems [indexPath.Row].ImageFilename)) {
    cell.UpdateCell (tableItems [indexPath.Row].Name
      , tableItems [indexPath.Row].Category
      , null);
  } else {
    cell.UpdateCell (tableItems [indexPath.Row].Name
      , tableItems [indexPath.Row].Category
      , UIImage.FromFile ("Images/" + tableItems [indexPath.Row].ImageFilename + ".jpg"));
  }

  return cell;
}

Bu yöntem, ekranda görüntülenecek her veri satırı için bir NativeiOSListViewCell örnek oluşturur. Örnek, NativeiOSCell her hücrenin düzenini ve hücre verilerini tanımlar. Kaydırma nedeniyle bir hücre ekrandan kaybolduğunda, hücre yeniden kullanılabilir hale getirilecektir. Bu, listedeki tüm veriler yerine yalnızca NativeiOSCell ekranda görüntülenen verilerin örneklerinin bulunduğundan emin olarak belleğin boşa harcanmasını önler. Hücre yeniden kullanımı hakkında daha fazla bilgi için bkz . Hücre Yeniden Kullanımı. Yöntemi GetCell ayrıca, mevcut olması koşuluyla her veri satırının özelliğini okur ImageFilename ve örneği satır için verilerle (ad, kategori ve görüntü) güncelleştirmeden NativeiOSListViewCell önce görüntüyü okur ve örnek UIImage olarak depolar.

NativeiOSListViewCell sınıfı her hücrenin düzenini tanımlar ve aşağıdaki kod örneğinde gösterilir:

public class NativeiOSListViewCell : UITableViewCell
{
  UILabel headingLabel, subheadingLabel;
  UIImageView imageView;

  public NativeiOSListViewCell (NSString cellId) : base (UITableViewCellStyle.Default, cellId)
  {
    SelectionStyle = UITableViewCellSelectionStyle.Gray;

    ContentView.BackgroundColor = UIColor.FromRGB (218, 255, 127);

    imageView = new UIImageView ();

    headingLabel = new UILabel () {
      Font = UIFont.FromName ("Cochin-BoldItalic", 22f),
      TextColor = UIColor.FromRGB (127, 51, 0),
      BackgroundColor = UIColor.Clear
    };

    subheadingLabel = new UILabel () {
      Font = UIFont.FromName ("AmericanTypewriter", 12f),
      TextColor = UIColor.FromRGB (38, 127, 0),
      TextAlignment = UITextAlignment.Center,
      BackgroundColor = UIColor.Clear
    };

    ContentView.Add (headingLabel);
    ContentView.Add (subheadingLabel);
    ContentView.Add (imageView);
  }

  public void UpdateCell (string caption, string subtitle, UIImage image)
  {
    headingLabel.Text = caption;
    subheadingLabel.Text = subtitle;
    imageView.Image = image;
  }

  public override void LayoutSubviews ()
  {
    base.LayoutSubviews ();

    headingLabel.Frame = new CoreGraphics.CGRect (5, 4, ContentView.Bounds.Width - 63, 25);
    subheadingLabel.Frame = new CoreGraphics.CGRect (100, 18, 100, 20);
    imageView.Frame = new CoreGraphics.CGRect (ContentView.Bounds.Width - 63, 5, 33, 33);
  }
}

Bu sınıf, hücrenin içeriğini ve bunların düzenini işlemek için kullanılan denetimleri tanımlar. OluşturucuNativeiOSListViewCell, ve UIImageView denetimlerinin UILabel örneklerini oluşturur ve görünümlerini başlatır. Bu denetimler, ve örneklerinde bu verileri ayarlamak için kullanılan yöntemle birlikte UpdateCell her satırın UILabel UIImageView verilerini görüntülemek için kullanılır. Bu örneklerin konumu geçersiz kılınan LayoutSubviews yöntem tarafından hücre içinde koordinatları belirtilerek ayarlanır.

Özel Denetimde Özellik Değişikliğine Yanıt Verme

NativeListView.Items Özellik değişirse, listeye eklenen veya listeden kaldırılan öğeler nedeniyle, özel işleyicinin değişiklikleri görüntüleyerek yanıt vermesi gerekir. Bu, aşağıdaki kod örneğinde gösterilen yöntemini geçersiz kılarak OnElementPropertyChanged gerçekleştirilebilir:

protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
  base.OnElementPropertyChanged (sender, e);

  if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
    Control.Source = new NativeiOSListViewSource (Element as NativeListView);
  }
}

yöntemi, bindable NativeListView.Items özelliğinin NativeiOSListViewSource değiştirilmesi koşuluyla denetime UITableView veri sağlayan sınıfının yeni bir örneğini oluşturur.

Android'de Özel oluşturucu oluşturma

Aşağıdaki kod örneği, Android platformu için özel işleyiciyi gösterir:

[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeAndroidListViewRenderer))]
namespace CustomRenderer.Droid
{
    public class NativeAndroidListViewRenderer : ListViewRenderer
    {
        Context _context;

        public NativeAndroidListViewRenderer(Context context) : base(context)
        {
            _context = context;
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                // unsubscribe
                Control.ItemClick -= OnItemClick;
            }

            if (e.NewElement != null)
            {
                // subscribe
                Control.Adapter = new NativeAndroidListViewAdapter(_context as Android.App.Activity, e.NewElement as NativeListView);
                Control.ItemClick += OnItemClick;
            }
        }
        ...

        void OnItemClick(object sender, Android.Widget.AdapterView.ItemClickEventArgs e)
        {
            ((NativeListView)Element).NotifyItemSelected(((NativeListView)Element).Items.ToList()[e.Position - 1]);
        }
    }
}

Özel işleyicinin yeni Xamarin.Forms bir öğeye bağlı olması koşuluyla yerel ListView denetim yapılandırılır. Bu yapılandırma, yerel ListView denetime veri sağlayan sınıfın NativeAndroidListViewAdapter bir örneğini oluşturmayı ve olayı işlemek için bir olay işleyicisi kaydetmeyi ItemClick içerir. Buna karşılık, bu işleyici özel denetim tarafından NativeListView sağlanan olayı çağırırItemSelected. İşleyicinin ItemClick ekli olduğu öğe değişikliklere bağlıysa Xamarin.Forms olayının aboneliği kaldırılır.

NativeAndroidListViewAdapter sınıfından BaseAdapter türetilir ve görüntülenecek veri listesini içeren bir Items özelliğin yanı sıra , GetView, GetItemIdve this[int] yöntemlerini geçersiz kılarak Countkullanıma sunar. Bu yöntem geçersiz kılmaları hakkında daha fazla bilgi için bkz . ListAdapter Uygulama. GetView yöntemi, her satır için verilerle doldurulmuş bir görünüm döndürür ve aşağıdaki kod örneğinde gösterilir:

public override View GetView (int position, View convertView, ViewGroup parent)
{
  var item = tableItems [position];

  var view = convertView;
  if (view == null) {
    // no view to re-use, create new
    view = context.LayoutInflater.Inflate (Resource.Layout.NativeAndroidListViewCell, null);
  }
  view.FindViewById<TextView> (Resource.Id.Text1).Text = item.Name;
  view.FindViewById<TextView> (Resource.Id.Text2).Text = item.Category;

  // grab the old image and dispose of it
  if (view.FindViewById<ImageView> (Resource.Id.Image).Drawable != null) {
    using (var image = view.FindViewById<ImageView> (Resource.Id.Image).Drawable as BitmapDrawable) {
      if (image != null) {
        if (image.Bitmap != null) {
          //image.Bitmap.Recycle ();
          image.Bitmap.Dispose ();
        }
      }
    }
  }

  // If a new image is required, display it
  if (!String.IsNullOrWhiteSpace (item.ImageFilename)) {
    context.Resources.GetBitmapAsync (item.ImageFilename).ContinueWith ((t) => {
      var bitmap = t.Result;
      if (bitmap != null) {
        view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (bitmap);
        bitmap.Dispose ();
      }
    }, TaskScheduler.FromCurrentSynchronizationContext ());
  } else {
    // clear the image
    view.FindViewById<ImageView> (Resource.Id.Image).SetImageBitmap (null);
  }

  return view;
}

GetView yöntemi, listedeki her veri satırı için işlenecek hücreyi olarak Viewdöndürmek için çağrılır. Ekranda görüntülenecek her veri satırı için bir View örnek oluşturur ve örneğin görünümü View bir düzen dosyasında tanımlanır. Kaydırma nedeniyle bir hücre ekrandan kaybolduğunda, hücre yeniden kullanılabilir hale getirilecektir. Bu, listedeki tüm veriler yerine yalnızca View ekranda görüntülenen verilerin örneklerinin bulunduğundan emin olarak belleğin boşa harcanmasını önler. Görünümü yeniden kullanma hakkında daha fazla bilgi için bkz . Satır Görünümü Yeniden Kullanımı.

GetView yöntemi ayrıca, özelliğinde ImageFilename belirtilen dosya adından View görüntü verilerini okumak da dahil olmak üzere örneği verilerle doldurur.

Yerel ListView tarafından ödenmemiş her hücrenin düzeni, yöntemi tarafından LayoutInflater.Inflate şişirilen düzen dosyasında tanımlanırNativeAndroidListViewCell.axml. Aşağıdaki kod örneği düzen tanımını gösterir:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:background="@drawable/CustomSelector">
    <LinearLayout
        android:id="@+id/Text"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="10dip">
        <TextView
            android:id="@+id/Text1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#FF7F3300"
            android:textSize="20dip"
            android:textStyle="italic" />
        <TextView
            android:id="@+id/Text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14dip"
            android:textColor="#FF267F00"
            android:paddingLeft="100dip" />
    </LinearLayout>
    <ImageView
        android:id="@+id/Image"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:padding="5dp"
        android:src="@drawable/icon"
        android:layout_alignParentRight="true" />
</RelativeLayout>

Bu düzen, hücrenin içeriğini görüntülemek için iki TextView denetimin ve bir ImageView denetimin kullanıldığını belirtir. İki TextView denetim bir denetim içinde LinearLayout dikey olarak yönlendirilir ve tüm denetimler içinde RelativeLayoutyer alır.

Özel Denetimde Özellik Değişikliğine Yanıt Verme

NativeListView.Items Özellik değişirse, listeye eklenen veya listeden kaldırılan öğeler nedeniyle, özel işleyicinin değişiklikleri görüntüleyerek yanıt vermesi gerekir. Bu, aşağıdaki kod örneğinde gösterilen yöntemini geçersiz kılarak OnElementPropertyChanged gerçekleştirilebilir:

protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
  base.OnElementPropertyChanged (sender, e);

  if (e.PropertyName == NativeListView.ItemsProperty.PropertyName) {
    Control.Adapter = new NativeAndroidListViewAdapter (_context as Android.App.Activity, Element as NativeListView);
  }
}

yöntemi, bağlanabilir NativeListView.Items özelliğin NativeAndroidListViewAdapter değiştirilmesi koşuluyla yerel ListView denetime veri sağlayan sınıfının yeni bir örneğini oluşturur.

UWP üzerinde Özel oluşturucu oluşturma

Aşağıdaki kod örneği, UWP için özel işleyiciyi gösterir:

[assembly: ExportRenderer(typeof(NativeListView), typeof(NativeUWPListViewRenderer))]
namespace CustomRenderer.UWP
{
    public class NativeUWPListViewRenderer : ListViewRenderer
    {
        ListView listView;

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
        {
            base.OnElementChanged(e);

            listView = Control as ListView;

            if (e.OldElement != null)
            {
                // Unsubscribe
                listView.SelectionChanged -= OnSelectedItemChanged;
            }

            if (e.NewElement != null)
            {
                listView.SelectionMode = ListViewSelectionMode.Single;
                listView.IsItemClickEnabled = false;
                listView.ItemsSource = ((NativeListView)e.NewElement).Items;             
                listView.ItemTemplate = App.Current.Resources["ListViewItemTemplate"] as Windows.UI.Xaml.DataTemplate;
                // Subscribe
                listView.SelectionChanged += OnSelectedItemChanged;
            }  
        }

        void OnSelectedItemChanged(object sender, SelectionChangedEventArgs e)
        {
            ((NativeListView)Element).NotifyItemSelected(listView.SelectedItem);
        }
    }
}

Özel işleyicinin yeni Xamarin.Forms bir öğeye bağlı olması koşuluyla yerel ListView denetim yapılandırılır. Bu yapılandırma, yerel ListView denetimin seçilen öğelere nasıl yanıt vereceğini ayarlamayı, denetim tarafından görüntülenen verileri doldurmayı, her hücrenin görünümünü ve içeriğini tanımlamayı ve olayı işlemek için bir olay işleyicisi kaydetmeyi SelectionChanged içerir. Buna karşılık, bu işleyici özel denetim tarafından NativeListView sağlanan olayı çağırırItemSelected. İşleyicinin SelectionChanged ekli olduğu öğe değişikliklere bağlıysa Xamarin.Forms olayının aboneliği kaldırılır.

Her yerel ListView hücrenin görünümü ve içeriği adlandırılmış ListViewItemTemplatebir DataTemplate tarafından tanımlanır. Bu DataTemplate , uygulama düzeyi kaynak sözlüğünde depolanır ve aşağıdaki kod örneğinde gösterilir:

<DataTemplate x:Key="ListViewItemTemplate">
    <Grid Background="#DAFF7F">
        <Grid.Resources>
            <local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.40*" />
            <ColumnDefinition Width="0.40*"/>
            <ColumnDefinition Width="0.20*" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22" VerticalAlignment="Top" Text="{Binding Name}" />
        <TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12" VerticalAlignment="Bottom" Text="{Binding Category}" />
        <Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
        <Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1" Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
    </Grid>
</DataTemplate>

hücrenin DataTemplate içeriğini ve bunların düzenini ve görünümünü görüntülemek için kullanılan denetimleri belirtir. Hücrenin içeriğini veri bağlama aracılığıyla görüntülemek için iki TextBlock denetim ve bir Image denetim kullanılır. Ayrıca, dosya uzantısını ConcatImageExtensionConverter her resim dosya adıyla birleştirmek .jpg için bir örneği kullanılır. Bu, denetimin Image özelliği ayarlandığında görüntüyü Source yükleyebilmesini ve işleyebilmesini sağlar.

Özel Denetimde Özellik Değişikliğine Yanıt Verme

NativeListView.Items Özellik değişirse, listeye eklenen veya listeden kaldırılan öğeler nedeniyle, özel işleyicinin değişiklikleri görüntüleyerek yanıt vermesi gerekir. Bu, aşağıdaki kod örneğinde gösterilen yöntemini geçersiz kılarak OnElementPropertyChanged gerçekleştirilebilir:

protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    base.OnElementPropertyChanged(sender, e);

    if (e.PropertyName == NativeListView.ItemsProperty.PropertyName)
    {
        listView.ItemsSource = ((NativeListView)Element).Items;
    }
}

yöntemi, yerel denetimi, bağlanabilir NativeListView.Items özelliğin ListView değiştirilmesi koşuluyla değiştirilen verilerle yeniden doldurur.

Özet

Bu makalede, platforma özgü liste denetimlerini ve yerel hücre düzenlerini kapsülleyen ve yerel liste denetimi performansı üzerinde daha fazla denetim sağlayan özel işleyicinin nasıl oluşturulacağı gösterilmiştir.