C# Xamarin表单列表视图项到GUI的动态更新
我已经在Xamarin表单中创建了一个ListView并绑定到视图模型中的可观察集合,通过调用OnPropertyChanged事件将项动态添加到ListView工作正常 但在从服务获取状态更新后,我正在更新相应的ListView项状态并调用OnPropertyChanged事件,以及将ListView项重新分配给它,但没有正确地更新GUI,有时正常工作,有时不正常 下面是我完成的示例代码C# Xamarin表单列表视图项到GUI的动态更新,c#,listview,xamarin,xamarin.forms,C#,Listview,Xamarin,Xamarin.forms,我已经在Xamarin表单中创建了一个ListView并绑定到视图模型中的可观察集合,通过调用OnPropertyChanged事件将项动态添加到ListView工作正常 但在从服务获取状态更新后,我正在更新相应的ListView项状态并调用OnPropertyChanged事件,以及将ListView项重新分配给它,但没有正确地更新GUI,有时正常工作,有时不正常 下面是我完成的示例代码 <ListView Grid.Row="3" HasUnevenRows="True" ItemsS
<ListView Grid.Row="3" HasUnevenRows="True" ItemsSource="{Binding ServiceList}" IsPullToRefreshEnabled="True" SeparatorColor="Black">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Spacing="4" Padding="5" BackgroundColor="LightGray">
<Label Text="{Binding OperationStatus, Converter={x:Static local:StatusMessageConverter.Default}}" FontSize="13" FontAttributes="Bold" TextColor="White" BackgroundColor="DarkCyan" />
<Label Text="{Binding Operation}" FontSize="10" Margin="10,0,0,0" />
<Label Text="{Binding OperationType}" FontSize="10" Margin="10,0,0,0" />
<Label Text="{Binding OperationStatus}" LineBreakMode="WordWrap" IsVisible="{Binding CanStatusVisible}" FontSize="10" Margin="10,0,0,0" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class ServiceViewModel : INotifyPropertyChanged
{
public ObservableCollection<ServiceItem> ServiceList
{
get
{
return _serviceList;
}
set
{
_serviceList = value;
OnPropertyChanged("ServiceList");
}
}
var tempList = new ObservableCollection<ServiceItem>();
tempList = ServiceList;
var targetItem = from item in tempList
where item.UniqueId == uniqueId
select item;
if (targetItem.Any())
{
var resultItem = targetItem.FirstOrDefault();
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}
ServiceList = null;
ServiceList = tempList;
OnPropertyChanged("ServiceList");
}
public class ServiceItem
{
public string UniqueId { get; set; }
public string Operation { get; set; }
public string OperationType { get; set; }
public string OperationStatus { get; set; }
public string StatusMessage { get; set; }
public bool CanStatusVisible { get; set; }
}
确保您的模型类继承上述注释中提到的InotifyPropertyChangedInterface
public class ServiceItem :INotifyPropertyChanged
{
private string uniqueId,operation,operationType,operationStatus,statusMessage;
private bool statusVisible;
public string UniqueId { get { return uniqueId; } set { uniqueId= value; RaisePropertyChanged(nameof(UniqueId)); } }
public string Operation { get { return operation; } set { operation= value; RaisePropertyChanged(nameof(Operation)); } }
public string OperationType { get { return operationType; } set { operationType= value; RaisePropertyChanged(nameof(OperationType)); } }
public string OperationStatus { get { return operationStatus; } set { operationStatus= value; RaisePropertyChanged(nameof(OperationStatus)); } }
public string StatusMessage { get { return statusMessage; } set { statusMessage= value; RaisePropertyChanged(nameof(StatusMessage)); } }
public bool CanStatusVisible { get { return statusVisible; } set { statusVisible= value; RaisePropertyChanged(nameof(CanStatusVisible )); } }
}
那么您的ViewModel代码应该如下所示:
var tempList = new ObservableCollection<ServiceItem>();
tempList = ServiceList;
var targetItem = from item in tempList
where item.UniqueId == uniqueId
select item;
if (targetItem.Any())
{
var resultItem = targetItem.FirstOrDefault();
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}
ServiceList = null;
ServiceList = tempList;
一旦您做了这些更改,您的代码应该可以工作了——以澄清我对FreakyAli的好答案的评论-- FreakyAli回答的关键部分是第一个代码片段:
public class ServiceItem :INotifyPropertyChanged
...
一旦这样做了,其他有问题的代码就可以大大简化。我认为,虽然我还没有测试过您可以替换Ali在下面显示的所有代码,但是您的ViewModel代码应该如下所示:使用:
也就是说,不需要创建临时列表,也不需要操作ServiceList。当您更改ServiceItem的属性时,该属性的RaisePropertyChanged将触发所需的显示刷新。您的ServiceItem类是否实现INotify属性Changed?我已将其添加到ViewModelas@BrunoCaceiro说,您的ServiceItem类需要实现INPC,以便UI收到其属性更改的通知Yep!我正在检查..:前两行被窃听:tempList需要是ServiceList的副本,而不是直接赋值。如前所述,ServiceList.Clear将清除圣殿骑士-而不是你想要的。最后两行:您是否在iOS X-Forms上测试过类似的代码?在这种情况下,它可能不适用,但iOS往往会崩溃,例外情况是第0节中的项数无效。if在一个方法调用中对一个列表执行两个操作。如果出现这种情况,请尝试注释ServiceList.Clear;。具体地说,我在删除一个项目并将其重新添加到列表中时遇到过这种情况-在这里可能没问题,因为替换了一个全新的列表。@ToolmakerSteve实际上我只是从问题中复制了代码,我并没有真正检查他在做什么。OK,但当您执行ServiceList.Clear时,您在他的代码中引入了一个不存在的错误。所以我不确定你想展示什么也许是你开始编辑的?好的,所需要的只是您对ServiceItem所做的更改—这将导致item UI根据需要进行更新。我相信他所有的代码都可以被删除。你怎么认为?
ServiceItem resultItem = ServiceList.Where(item => item.UniqueId == uniqueId).FirstOrDefault();
if (resultItem != null)
{
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}