Xamarin.iOS CollectionView - 添加新元素会导致整个列表被刷新
Xamarin.iOS CollectionView - Adding a new element causes the whole list to be refreshed
我正在构建一个 xamarin.forms 聊天应用程序并且只需要添加交付的新元素,在 Android 我有预期的行为,但是 iOS 刷新所有 CollectionView是什么导致了糟糕的用户体验。请查看我的代码(仅相关部分),让我知道我做错了什么,或者我也错过了在 iOS 上出现此行为的原因。
我的.xaml:
<CollectionView x:Name="ChatCollectionView"
SelectionMode="None" HorizontalScrollBarVisibility="Never"
VerticalScrollBarVisibility="Always" ItemsUpdatingScrollMode="KeepLastItemInView"
ItemTemplate="{StaticResource MsgTemplateSelector}" Margin="5,0,5,10">
</CollectionView>
.cs 文件:
public static ReaderWriterLockSlim valuesLock = new ReaderWriterLockSlim();
void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
{
var collectionLock = (ReaderWriterLockSlim)context;
Action enterLock = writeAccess ? new Action(collectionLock.EnterWriteLock) : new Action(collectionLock.EnterReadLock);
Action exitLock = writeAccess ? new Action(collectionLock.ExitWriteLock) : new Action(collectionLock.ExitReadLock);
enterLock();
try { accessMethod(); } finally { exitLock(); }
}
ObservableCollection<Msg> ListMsg;
public Page(string userid, string chatkey, string titulo, string foto)
{
// some code ...
this.BindingContext = this;
BindingBase.EnableCollectionSynchronization(ListMsg as IEnumerable, valuesLock,ObservableCollectionCallback);
List<Msg> recipient = await Task.Run(()=> client.PostData<List<Msg>>("url/msg.php"));
//previous line returns a json and deserialize it to a list of "Msg"
if (recipient != null)
{
ListMsg = new ObservableCollection<Msg>(recipient);
ChatCollectionView.ItemsSource = ListMsg;
if (ListMsg.Count > 0)
{
if(Device.RuntimePlatform==Device.iOS)
await Task.Delay(2000);
ChatCollectionView.ScrollTo(ListMsg.Count - 1, position: ScrollToPosition.End, animate: false);
}
}
else
ChatCollectionView.ItemsSource = new ObservableCollection<Msg>();
MessagingCenter.Subscribe<MainPage, Msg>("Page", "scroll", async (sender, arg) =>
{
Task.WaitAll(tasks.ToArray());
tasks.Add(Task.Run(async () =>
{
arg = await MsgPrepare(arg); //this only changes the element arg not the list
_ = Device.InvokeOnMainThreadAsync(() =>
{
valuesLock.EnterWriteLock();
try { ListMsg.Add(arg); }
finally { valuesLock.ExitWriteLock(); }
});
}));
}
}
“错误”地修复了它。我添加了涉及整个页面来修复 iOS 软键盘(覆盖了聚焦的 Entry 元素)和宾果游戏的问题,它已经解决了这两个问题。如果我取下 ScrollView,问题又来了。我还注意到,如果 ScrollView 仅包含 CollectionView,它就可以工作,它不需要像我的情况那样包围整个页面。另一点是如果你不想要 ScrollView 的滚动特性,你可以设置 Orientation=Neither 来避免它。希望对大家有帮助。
我正在构建一个 xamarin.forms 聊天应用程序并且只需要添加交付的新元素,在 Android 我有预期的行为,但是 iOS 刷新所有 CollectionView是什么导致了糟糕的用户体验。请查看我的代码(仅相关部分),让我知道我做错了什么,或者我也错过了在 iOS 上出现此行为的原因。
我的.xaml:
<CollectionView x:Name="ChatCollectionView"
SelectionMode="None" HorizontalScrollBarVisibility="Never"
VerticalScrollBarVisibility="Always" ItemsUpdatingScrollMode="KeepLastItemInView"
ItemTemplate="{StaticResource MsgTemplateSelector}" Margin="5,0,5,10">
</CollectionView>
.cs 文件:
public static ReaderWriterLockSlim valuesLock = new ReaderWriterLockSlim();
void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
{
var collectionLock = (ReaderWriterLockSlim)context;
Action enterLock = writeAccess ? new Action(collectionLock.EnterWriteLock) : new Action(collectionLock.EnterReadLock);
Action exitLock = writeAccess ? new Action(collectionLock.ExitWriteLock) : new Action(collectionLock.ExitReadLock);
enterLock();
try { accessMethod(); } finally { exitLock(); }
}
ObservableCollection<Msg> ListMsg;
public Page(string userid, string chatkey, string titulo, string foto)
{
// some code ...
this.BindingContext = this;
BindingBase.EnableCollectionSynchronization(ListMsg as IEnumerable, valuesLock,ObservableCollectionCallback);
List<Msg> recipient = await Task.Run(()=> client.PostData<List<Msg>>("url/msg.php"));
//previous line returns a json and deserialize it to a list of "Msg"
if (recipient != null)
{
ListMsg = new ObservableCollection<Msg>(recipient);
ChatCollectionView.ItemsSource = ListMsg;
if (ListMsg.Count > 0)
{
if(Device.RuntimePlatform==Device.iOS)
await Task.Delay(2000);
ChatCollectionView.ScrollTo(ListMsg.Count - 1, position: ScrollToPosition.End, animate: false);
}
}
else
ChatCollectionView.ItemsSource = new ObservableCollection<Msg>();
MessagingCenter.Subscribe<MainPage, Msg>("Page", "scroll", async (sender, arg) =>
{
Task.WaitAll(tasks.ToArray());
tasks.Add(Task.Run(async () =>
{
arg = await MsgPrepare(arg); //this only changes the element arg not the list
_ = Device.InvokeOnMainThreadAsync(() =>
{
valuesLock.EnterWriteLock();
try { ListMsg.Add(arg); }
finally { valuesLock.ExitWriteLock(); }
});
}));
}
}
“错误”地修复了它。我添加了涉及整个页面来修复 iOS 软键盘(覆盖了聚焦的 Entry 元素)和宾果游戏的问题,它已经解决了这两个问题。如果我取下 ScrollView,问题又来了。我还注意到,如果 ScrollView 仅包含 CollectionView,它就可以工作,它不需要像我的情况那样包围整个页面。另一点是如果你不想要 ScrollView 的滚动特性,你可以设置 Orientation=Neither 来避免它。希望对大家有帮助。