Xamarin 将 ListView 项动态更新到 GUI

Posted

技术标签:

【中文标题】Xamarin 将 ListView 项动态更新到 GUI【英文标题】:Xamarin forms ListView item dynamic update to GUI 【发布时间】:2019-06-30 15:56:22 【问题描述】:

我在 Xamarin 表单中创建了一个 ListView 并绑定到视图模型中的 Observable 集合,通过调用 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; 

【问题讨论】:

您的 ServiceItem 类是否实现了 INotify PropertyChanged? 我已将其添加到 ViewModel 正如@BrunoCaceiro 所说,您的 ServiceItem 类需要实现 INPC 以便通知 UI 其属性的更改 是的!我正在检查.. :) 【参考方案1】:

请注意您的模型类继承自INotifyPropertyChangedinterface(如上面的 cmets 中所述)。

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;

完成这些更改后,您的代码应该可以工作

【讨论】:

前两行有问题:tempList 需要是ServiceList副本,而不是直接赋值。如所写,ServiceList.Clear 将清除 tempList - 不是您想要的。最后两行:您是否在 ios X-Forms 上测试过类似的代码?它可能不适用于这种情况,但如果在单个方法调用中对列表执行两个操作,iOS 往往会崩溃并出现异常 "Invalid number of items in section 0."。如果发生这种情况,请尝试注释掉 ServiceList.Clear();。具体来说,当删除并将项目重新添加到列表时,我会发生这种情况 - 在这里可能还可以,因为替换了一个全新的列表。 @ToolmakerSteve 实际上我只是从问题中复制了代码,我并没有真正检查他在做什么 好的,但是当您执行ServiceList.Clear() 时,您引入了他的代码中不存在的错误。所以我不确定你想在那里展示什么。 - 也许是您开始进行的编辑? AFAIK,所需要的只是您对ServiceItem 所做的更改 - 这应该会导致项目 UI 根据需要进行更新。我相信他所有直接与 ServiceList 混淆的代码都可以删除。你怎么看?【参考方案2】:

--- 澄清我对 FreakyAli 的好答案的评论---

FreakyAli 回答的本质部分是第一个代码 sn-p:

public class ServiceItem :INotifyPropertyChanged
...

一旦完成,其他有问题的代码就可以大大简化。我认为(虽然我没有测试过)你可以替换 all Ali 在 “然后你的 ViewModel 代码应该看起来像这样:” 下显示的代码:

ServiceItem resultItem = ServiceList.Where(item => item.UniqueId == uniqueId).FirstOrDefault();
if (resultItem != null)

    resultItem.CanStatusVisible = true;
    resultItem.OperationStatus = string.Format("0: 1", "Status Message", resultMessage);

也就是说,不需要创建临时列表,也不需要操作ServiceList。当您更改 ServiceItem 的属性时,该属性的 RaisePropertyChanged 将触发所需的显示刷新。

【讨论】:

以上是关于Xamarin 将 ListView 项动态更新到 GUI的主要内容,如果未能解决你的问题,请参考以下文章

使用 Prism Xamarin 表单创建动态 TabbedPage

Xamarin Listview 仅添加 1 项我的列表中有 2 项

ListView 中突出显示的选定项 Xamarin.Forms

更新 ObservableCollection 无法正确更新 Xamarin 表单中的 ListView

Xamarin 中 StackLayout 内的 ListView 未根据列表视图项高度扩展

Xamarin.Forms ListView:设置点击项的突出显示颜色