Xamarin Forms Listview 不更新 GUI
Xamarin Forms Listview Not Updating GUI
我正在尝试创建一个聊天页面。有一个列表视图,其 itemssource 是一个 ObservableCollection。在将一个项目添加到 ObservableCollection 之前,一切似乎都很顺利。添加的项目不会立即出现在屏幕上,只有在触摸屏幕后才会出现。
事实上,我遇到了与此处所述相同的问题:https://forums.xamarin.com/discussion/18631/listview-binding-to-observablecollection-does-not-update-gui/p2
我认为线程(第 2 页)中所述的解决方案之一与 INotifyPropertyChanged 有关。经过多次尝试应用该解决方案以满足我的需求后,我无法这样做。那么能否请您指导我正确的方向。
我的代码总结如下:
public partial class Chat : ContentPage
{
private ObservableCollection<MessageObj> Messages = new ObservableCollection<MessageObj>();
public Chat(string name, string imageURL, int UID)
{
msgList.ItemsSource = Messages; //msgList is ListView in XAML
}
public class MessageObj
{
public string Mess { get; set; }
public TextAlignment textAlignment { get; set; }
public MessageObj(string Mess, TextAlignment textAlignment)
{
this.Mess = Mess;
this.textAlignment = textAlignment;
}
}
}
我还阅读了: 我想我正在更改集合,所以我不应该面对这个问题,但我确实遇到了。
任何 help/insight 将不胜感激!
我添加了一个要点,其中包含我的参考代码,其中显示了我现在对不同解决方案的评论尝试:https://gist.github.com/Dobermensch/49ee9d8adb9a83a38790b691c857691d
编辑:向要点添加了一些最初省略的代码
Edit2:仅供参考,我没有使用 MVVM 模式。
正如您在评论中阐明的那样,问题出在从 SendBird API 的 OnMessageReceived 回调期间接收到的消息。通过阅读他们的文档,他们似乎没有与 UI 线程同步调用回调。
Xamarin 应用程序可以是多线程的,有一个 UI 主线程,必须 参与对 UI 的所有更新。在许多应用程序中,您编写的代码将全部 运行 在 UI 线程上,除非您执行 Task.Run()
或 await <some async task>.ConfigureAwait(false)
之类的操作以强制关闭 UI线程。所以通常你不必担心 UI 与非 UI 线程。来自用户与 UI 交互的回调,如按钮点击,以及 UI 线程上的 运行。来自非 UI 源的回调可能在也可能不在 UI 线程上(取决于实现和运气),我怀疑这里就是这种情况。
根据您正在使用的平台,如果您尝试从非 UI 线程的代码更改 UI,可能会出现不同的错误。有时您会遇到崩溃(典型的 iOS 响应),或者不会立即更新(常见的 Android 行为)。
所以我会尝试使用 Device.BeginInvokeOnMainThread 强制在 UI 线程上进行集合更新,例如:
ch.OnMessageReceived = (BaseChannel baseChannel, BaseMessage baseMessage) => {
Device.BeginInvokeOnMainThread(() =>
{
Messages.Add(new MessageObj(((UserMessage)baseMessage).Message, TextAlignment.Start));
msgList.ScrollTo(Messages.Last(), ScrollToPosition.End, false);
};
};
这将告诉 UI 线程完成将 MessageObj 添加到 Messages 的工作,因此各种 PropertyChanged 事件也将在 UI 线程上处理,该线程知道如何实际更新 UI.
我有一个类似的问题,我发现,经过大量调试和测试后,GUI 没有更新,因为 ItemsSource
和 ListView
而不是 因为 ObservableCollection
.
将 ItemsSource
设置为空,然后使用 ObservableCollection
再次设置它使 GUI 更新。
虽然我希望有更优雅的解决方案,但我找不到。
Device.BeginInvokeOnMainThread(() => {
Context.WarmupOptions[0].IsChecked = !Context.WarmupOptions[0].IsChecked;
mylist.ItemsSource = null;
mylist.ItemsSource = Context.WarmupOptions;
});
我正在尝试创建一个聊天页面。有一个列表视图,其 itemssource 是一个 ObservableCollection。在将一个项目添加到 ObservableCollection 之前,一切似乎都很顺利。添加的项目不会立即出现在屏幕上,只有在触摸屏幕后才会出现。
事实上,我遇到了与此处所述相同的问题:https://forums.xamarin.com/discussion/18631/listview-binding-to-observablecollection-does-not-update-gui/p2
我认为线程(第 2 页)中所述的解决方案之一与 INotifyPropertyChanged 有关。经过多次尝试应用该解决方案以满足我的需求后,我无法这样做。那么能否请您指导我正确的方向。
我的代码总结如下:
public partial class Chat : ContentPage
{
private ObservableCollection<MessageObj> Messages = new ObservableCollection<MessageObj>();
public Chat(string name, string imageURL, int UID)
{
msgList.ItemsSource = Messages; //msgList is ListView in XAML
}
public class MessageObj
{
public string Mess { get; set; }
public TextAlignment textAlignment { get; set; }
public MessageObj(string Mess, TextAlignment textAlignment)
{
this.Mess = Mess;
this.textAlignment = textAlignment;
}
}
}
我还阅读了:
我添加了一个要点,其中包含我的参考代码,其中显示了我现在对不同解决方案的评论尝试:https://gist.github.com/Dobermensch/49ee9d8adb9a83a38790b691c857691d
编辑:向要点添加了一些最初省略的代码
Edit2:仅供参考,我没有使用 MVVM 模式。
正如您在评论中阐明的那样,问题出在从 SendBird API 的 OnMessageReceived 回调期间接收到的消息。通过阅读他们的文档,他们似乎没有与 UI 线程同步调用回调。
Xamarin 应用程序可以是多线程的,有一个 UI 主线程,必须 参与对 UI 的所有更新。在许多应用程序中,您编写的代码将全部 运行 在 UI 线程上,除非您执行 Task.Run()
或 await <some async task>.ConfigureAwait(false)
之类的操作以强制关闭 UI线程。所以通常你不必担心 UI 与非 UI 线程。来自用户与 UI 交互的回调,如按钮点击,以及 UI 线程上的 运行。来自非 UI 源的回调可能在也可能不在 UI 线程上(取决于实现和运气),我怀疑这里就是这种情况。
根据您正在使用的平台,如果您尝试从非 UI 线程的代码更改 UI,可能会出现不同的错误。有时您会遇到崩溃(典型的 iOS 响应),或者不会立即更新(常见的 Android 行为)。
所以我会尝试使用 Device.BeginInvokeOnMainThread 强制在 UI 线程上进行集合更新,例如:
ch.OnMessageReceived = (BaseChannel baseChannel, BaseMessage baseMessage) => {
Device.BeginInvokeOnMainThread(() =>
{
Messages.Add(new MessageObj(((UserMessage)baseMessage).Message, TextAlignment.Start));
msgList.ScrollTo(Messages.Last(), ScrollToPosition.End, false);
};
};
这将告诉 UI 线程完成将 MessageObj 添加到 Messages 的工作,因此各种 PropertyChanged 事件也将在 UI 线程上处理,该线程知道如何实际更新 UI.
我有一个类似的问题,我发现,经过大量调试和测试后,GUI 没有更新,因为 ItemsSource
和 ListView
而不是 因为 ObservableCollection
.
将 ItemsSource
设置为空,然后使用 ObservableCollection
再次设置它使 GUI 更新。
虽然我希望有更优雅的解决方案,但我找不到。
Device.BeginInvokeOnMainThread(() => {
Context.WarmupOptions[0].IsChecked = !Context.WarmupOptions[0].IsChecked;
mylist.ItemsSource = null;
mylist.ItemsSource = Context.WarmupOptions;
});