C# Xamarin表单列表视图项到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

我已经在Xamarin表单中创建了一个ListView并绑定到视图模型中的可观察集合,通过调用OnPropertyChanged事件将项动态添加到ListView工作正常

但在从服务获取状态更新后,我正在更新相应的ListView项状态并调用OnPropertyChanged事件,以及将ListView项重新分配给它,但没有正确地更新GUI,有时正常工作,有时不正常

下面是我完成的示例代码

<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);
}