【问题标题】:Xamarin forms ListView item dynamic update to GUIXamarin 将 ListView 项动态更新到 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 其属性的更改
  • 是的!我正在检查.. :)

标签: c# listview xamarin xamarin.forms


【解决方案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 将触发所需的显示刷新。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    相关资源
    最近更新 更多