简体   繁体   English

Xamarin 表单 ListView 项动态更新到 GUI

[英]Xamarin forms ListView item dynamic update to GUI

I've created a ListView in Xamarin form and bind to Observable collection in view model, adding item dynamically to ListView is working fine by calling OnPropertyChanged event.我以 Xamarin 形式创建了一个 ListView 并绑定到视图模型中的 Observable 集合,通过调用 OnPropertyChanged 事件将项目动态添加到 ListView 工作正常。

But after getting status update from service I'm updating corresponding ListView item status and calling OnPropertyChanged event as well as re-assigining the ListView items to it but didn't get updated GUI properly sometimes working and some times not.但是在从服务获取状态更新后,我正在更新相应的 ListView 项目状态并调用 OnPropertyChanged 事件以及将 ListView 项目重新分配给它,但没有得到更新的 GUI 有时正常工作,有时没有。

Below is the sample code that I've done.下面是我完成的示例代码。

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

See to it that your model class inherits from INotifyPropertyChanged interface(as mentioned in the above comments).确保您的模型类继承自INotifyPropertyChanged接口(如上述评论中所述)。

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

Then your ViewModel code should look something like this:那么您的 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;

Once you do these changes your code should work完成这些更改后,您的代码应该可以工作

--- To clarify my comment on FreakyAli's good answer --- ---澄清我对FreakyAli的好答案的评论---

The essential part of FreakyAli's answer is the first code snippet: FreakyAli 回答的重要部分是第一个代码片段:

public class ServiceItem :INotifyPropertyChanged
...

Once that is done, the other code in question can be greatly simplified.一旦完成,可以大大简化其他有问题的代码。 I think (though I have not tested) that you can replace all the code Ali shows under "Then your ViewModel code should look something like this:" with:我认为(虽然我没有测试过)您可以将 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);
}

That is, it is not necessary to create a temp list, nor to manipulate ServiceList .也就是说,不需要创建临时列表,也不需要操作ServiceList When you change the property of a ServiceItem , that property's RaisePropertyChanged will trigger the needed display refresh.当您更改ServiceItem的属性时,该属性的RaisePropertyChanged将触发所需的显示刷新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM