5

Ich versuche, eine benutzerdefinierte Ansicht in Xamarin Forms, die in eine UICollectionView in IOS übersetzt.Xamarin Forms UICollectionView mit DataTemplate

Das erste, was ziemlich einfach ist zu tun:

Ausblick:

public class CollectionView : View 
{ 

} 

Renderer:

public class CollectionViewRenderer : ViewRenderer<CollectionView, UICollectionView> 
{ 

    protected override void OnElementChanged(ElementChangedEventArgs<CollectionView> e) 
    { 
     base.OnElementChanged(e); 

     if (Control == null) 
     { 
      SetNativeControl(new UICollectionView(new CGRect(0, 0, 200, 200), new UICollectionViewFlowLayout())); 
     } 

     if (e.NewElement != null) 
     { 
      ... 
      Control.Source = new CollectionViewSource(a, this); 
      Control.ReloadData(); 
     } 
    } 
} 

Nun möchte Ich mag diese Collection mit Datatemplates füttern (von Datatemplateselector) . Aber ich bin nicht in der Lage, einen Weg finden, um die Klassen zu registrieren:

Von der Vorlage, die Sie tun können:

Template.CreateContent(); 

das UI-Element zu erhalten.

Aber wie kann ich es in der Collection registrieren im CollectionSource

für dequeue'ing

z.B .:

CollectionView.RegisterClassForCell(typeof(????), "CellId"); 

Antwort

0

Hoffnung, es wird Ihnen helfen !!!

Custom

GridCollectionView.cs

using System; 
using CoreGraphics; 
using Foundation; 
using UIKit; 


namespace MyApp.Forms.Controls 
{ 
    public class GridCollectionView : UICollectionView 
    { 
     public GridCollectionView() : this (default(CGRect)) 
     { 
     } 


     public GridCollectionView(CGRect frm) 
      : base(frm, new UICollectionViewFlowLayout()) 
     { 
      AutoresizingMask = UIViewAutoresizing.All; 
      ContentMode = UIViewContentMode.ScaleToFill; 
      RegisterClassForCell(typeof(GridViewCell), new NSString (GridViewCell.Key)); 
     } 


     public bool SelectionEnable 
     { 
      get; 
      set; 
     } 


     public double RowSpacing 
     { 
      get 
      { 
       return ((UICollectionViewFlowLayout)this.CollectionViewLayout).MinimumLineSpacing; 
      } 
      set 
      { 
       ((UICollectionViewFlowLayout)this.CollectionViewLayout).MinimumLineSpacing = (nfloat)value; 
      } 
     } 


     public double ColumnSpacing 
     { 
      get 
      { 
       return ((UICollectionViewFlowLayout)this.CollectionViewLayout).MinimumInteritemSpacing; 
      } 
      set 
      { 
       ((UICollectionViewFlowLayout)this.CollectionViewLayout).MinimumInteritemSpacing = (nfloat)value; 
      } 
     } 


     public CGSize ItemSize 
     { 
      get 
      { 
       return ((UICollectionViewFlowLayout)this.CollectionViewLayout).ItemSize; 
      } 
      set 
      { 
       ((UICollectionViewFlowLayout)this.CollectionViewLayout).ItemSize = value; 
      } 
     } 


     public override UICollectionViewCell CellForItem(NSIndexPath indexPath) 
     { 
      if (indexPath == null) 
      { 
       //calling base.CellForItem(indexPath) when indexPath is null causes an exception. 
       //indexPath could be null in the following scenario: 
       // - GridView is configured to show 2 cells per row and there are 3 items in ItemsSource collection 
       // - you're trying to drag 4th cell (empty) like you're trying to scroll 
       return null; 
      } 
      return base.CellForItem(indexPath); 
     } 


     public override void Draw (CGRect rect) 
     { 
      this.CollectionViewLayout.InvalidateLayout(); 


      base.Draw (rect); 
     } 


     public override CGSize SizeThatFits(CGSize size) 
     { 
      return ItemSize; 
     } 
    } 
} 

Renderer Klasse

GridViewRenderer.cs

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.Linq; 
using Foundation; 
using UIKit; 
using Xamarin.Forms; 
using Xamarin.Forms.Platform.iOS; 
using MyApp.Controls; 
using System.Collections.Generic; 


[assembly: ExportRenderer (typeof(GridView), typeof(GridViewRenderer))] 
namespace MyApp.Controls 
{ 
    public class GridViewRenderer: ViewRenderer<GridView,GridCollectionView> 
    { 
     private GridDataSource _dataSource; 

    public GridViewRenderer() 
     { 
     } 

     public int RowsInSection(UICollectionView collectionView, nint section) 
     { 
      return ((ICollection) this.Element.ItemsSource).Count; 
     } 

     public void ItemSelected(UICollectionView tableView, NSIndexPath indexPath) 
     { 
      var item = this.Element.ItemsSource.Cast<object>().ElementAt(indexPath.Row); 
      this.Element.InvokeItemSelectedEvent(this, item); 
     } 

     public UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) 
     { 
      var item = this.Element.ItemsSource.Cast<object>().ElementAt(indexPath.Row); 
      var viewCellBinded = (this.Element.ItemTemplate.CreateContent() as ViewCell); 
      if (viewCellBinded == null) return null; 


      viewCellBinded.BindingContext = item; 
      return this.GetCell(collectionView, viewCellBinded, indexPath); 
     } 


     protected virtual UICollectionViewCell GetCell(UICollectionView collectionView, ViewCell item, NSIndexPath indexPath) 
     { 
      var collectionCell = collectionView.DequeueReusableCell(new NSString(GridViewCell.Key), indexPath) as GridViewCell; 


      if (collectionCell == null) return null; 


      collectionCell.ViewCell = item; 


      return collectionCell; 
     } 


     protected override void OnElementChanged (ElementChangedEventArgs<GridView> e) 
     { 
      base.OnElementChanged (e); 
      if (e.OldElement != null) 
      { 
       Unbind (e.OldElement); 
      } 
      if (e.NewElement != null) 
      { 
       if (Control == null) 
       { 
        var collectionView = new GridCollectionView() { 
         AllowsMultipleSelection = false, 
         SelectionEnable = e.NewElement.SelectionEnabled, 
         ContentInset = new UIEdgeInsets ((float)this.Element.Padding.Top, (float)this.Element.Padding.Left, (float)this.Element.Padding.Bottom, (float)this.Element.Padding.Right), 
         BackgroundColor = this.Element.BackgroundColor.ToUIColor(), 
         ItemSize = new CoreGraphics.CGSize ((float)this.Element.ItemWidth, (float)this.Element.ItemHeight), 
         RowSpacing = this.Element.RowSpacing, 
         ColumnSpacing = this.Element.ColumnSpacing 
        }; 


        Bind (e.NewElement); 


        collectionView.Source = this.DataSource; 
        //collectionView.Delegate = this.GridViewDelegate; 


        SetNativeControl (collectionView); 
       } 
      } 




     } 


     private void Unbind (GridView oldElement) 
     { 
      if (oldElement == null) return; 


      oldElement.PropertyChanging -= this.ElementPropertyChanging; 
      oldElement.PropertyChanged -= this.ElementPropertyChanged; 


      var itemsSource = oldElement.ItemsSource as INotifyCollectionChanged; 
      if (itemsSource != null) 
      { 
       itemsSource.CollectionChanged -= this.DataCollectionChanged; 
      } 
     } 


     private void Bind (GridView newElement) 
     { 
      if (newElement == null) return; 


      newElement.PropertyChanging += this.ElementPropertyChanging; 
      newElement.PropertyChanged += this.ElementPropertyChanged; 


      var source = newElement.ItemsSource as INotifyCollectionChanged; 
      if (source != null) 
      { 
       source.CollectionChanged += this.DataCollectionChanged; 
      } 
     } 


     private void ElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) 
     { 
      if (e.PropertyName == GridView.ItemsSourceProperty.PropertyName) 
      { 
       var newItemsSource = this.Element.ItemsSource as INotifyCollectionChanged; 
       if (newItemsSource != null) 
       { 
        newItemsSource.CollectionChanged += DataCollectionChanged; 
        this.Control.ReloadData(); 
       } 
      } 
      else if(e.PropertyName == "ItemWidth" || e.PropertyName == "ItemHeight") 
      { 
       this.Control.ItemSize = new CoreGraphics.CGSize ((float)this.Element.ItemWidth, (float)this.Element.ItemHeight); 
      } 
     } 


     private void ElementPropertyChanging (object sender, PropertyChangingEventArgs e) 
     { 
      if (e.PropertyName == "ItemsSource") 
      { 
       var oldItemsSource = this.Element.ItemsSource as INotifyCollectionChanged; 
       if (oldItemsSource != null) 
       { 
        oldItemsSource.CollectionChanged -= DataCollectionChanged; 
       } 
      } 
     } 


     private void DataCollectionChanged (object sender, NotifyCollectionChangedEventArgs e) 
     { 
      InvokeOnMainThread (()=> { 
       try 
       { 
        if(this.Control == null) 
         return; 


        this.Control.ReloadData(); 


        // TODO: try to handle add or remove operations gracefully, just reload the whole collection for other changes 
        // InsertItems, DeleteItems or ReloadItems can cause 
        // *** Assertion failure in -[XLabs_Forms_Controls_GridCollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:], 
        // BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.30.14/UICollectionView.m:4324 


//     var indexes = new List<NSIndexPath>(); 
//     switch (e.Action) { 
//      case NotifyCollectionChangedAction.Add: 
//       for (int i = 0; i < e.NewItems.Count; i++) { 
//        indexes.Add(NSIndexPath.FromRowSection((nint)(e.NewStartingIndex + i),0)); 
//       } 
//       this.Control.InsertItems(indexes.ToArray()); 
//       break; 
//      case NotifyCollectionChangedAction.Remove: 
//       for (int i = 0; i< e.OldItems.Count; i++) { 
//        indexes.Add(NSIndexPath.FromRowSection((nint)(e.OldStartingIndex + i),0)); 
//       } 
//       this.Control.DeleteItems(indexes.ToArray()); 
//       break; 
//      default: 
//       this.Control.ReloadData(); 
//       break; 
//     } 
       } 
       catch { } // todo: determine why we are hiding a possible exception here 
      }); 
     } 

     private GridDataSource DataSource 
     { 
      get 
      { 
       return _dataSource ?? (_dataSource = new GridDataSource (GetCell, RowsInSection,ItemSelected)); 
      } 
     } 


     protected override void Dispose (bool disposing) 
     { 
      base.Dispose (disposing); 
      if (disposing && _dataSource != null) 
      { 
       Unbind (Element); 
       _dataSource.Dispose(); 
       _dataSource = null; 
      } 
     } 
    } 
} 

Weitere Informationen Click here for custom class und click here for renderer class

+0

Hey danke für den Link, es ist interessant. Sie scheinen die Zellen nicht zu registrieren, sondern entziehen sie nur. https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/src/Forms/XLabs.Forms.iOS/Controls/GridView/GridViewRenderer.cs#L89 – RVandersteen

+0

Ich denke, Sie haben für die Link-Only-Antwort gewählt . – RVandersteen

+0

@RVandersteen, ich habe meine Antwort aktualisiert. –