我正在创建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”函数并使用反射调用它们,但我希望找到更简单的东西...
答案 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 });
}