Xamarin形成C#:将IEnumerable转换为ObservableCollection<>

时间:2017-12-14 17:04:49

标签: c# xaml listview

我正在创建ListView的替代品,允许用户重新排列UI中的项目。

但是如果使用这个新ListView的屏幕想要知道何时重新排列项目,它会将ItemsSource属性设置为ObservableCollection,然后期望在重新排列项目时被告知。

XAML:

<Layout>
   <MyListView x:Name="MyList">
</Layout>

代码背后:

public class MyScreen
{
   ObservableCollection<MyItem> Items = new ObservableCollection<MyItem>();

   public MyScreen()
   {
      InitializeComponent();

      MyList.ItemsSource = Items;
      Items.CollectionChanged += OnItemsChanged;
   }
}

MyListView.cs:

public class MyListView : AbsoluteLayout
{
   public static readonly BindableProperty ItemsSourceProperty =
        BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(MyListView), null);
   public IEnumerable ItemsSource
   {
      get { return (IEnumerable)this.GetValue(ItemsSourceProperty); }
      set { this.SetValue(ItemsSourceProperty, value); }
   }

   public void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      if (propertyName == nameof(ItemsSource))
      {
         foreach (object item in ItemsSource)
         {
            // Create a visual element, and set the BindingContext of that
            // visual element to 'item'
         }
      }
   }

   public void RearrangeItem(int beforeIndex, int afterIndex)
   {
      if (ItemsSource is ObservableCollection<ARGH> collection)
      {
         collection.RemoveAt(...);
         collection.Insert(...);
      }
   }
}

你看到了问题。我不能在不知道集合中对象类型的情况下将ItemsSource(IEnumerable与Xamarin.Forms.ListView的一致性)转换为ObservableCollection,最直接的方法是让MyListView也是通用的,但是因为我在XAML中创建了MyListView,所以我不能这样做。

我确信我可以用反射做一些聪明的东西,我问ItemsSource它是否来自任何ObservableCollection,如果是这样,找到“RemoveAt”和“Insert”函数并使用反射调用它们,但我希望找到更简单的东西...

2 个答案:

答案 0 :(得分:1)

ObservableCollection<T>实现非通用IList接口,因此您可以转换为该接口并调用RemoveAt()&amp; Insert()传递object

答案 1 :(得分:0)

如果您只需要RemoveAt()和Insert(),那么SLaks答案是最简单的; for Move()这就是我最终的结果,这样我就可以在IEnumerable上调用ObservableCollection&lt;&gt; .Move(oldIndex,newIndex):

Type t = ItemsSource.GetType();
if (t.Name == "ObservableCollection`1")
{
   MethodInfo method = t.GetRuntimeMethod("Move", new Type[] { typeof(Int32), typeof(Int32) });
   method.Invoke(ItemsSource, new object[] { oldIndex, newIndex });
}