【问题标题】:View does not show ViewModel property changes after async operation异步操作后视图不显示 ViewModel 属性更改
【发布时间】:2018-02-12 05:47:35
【问题描述】:

我的 ViewModel 有一个 30 秒的数据刷新服务委托方法:

public Task OnDataRefreshed(List<MyType> data)
{
    this.Data = data;
    LongRunningGetDetailsAsync();
    return Task.FromResult(0);
} 

公共属性Data 在视图中正确显示和刷新。

此处的目的不是等待异步任务(即发即弃)LongRunningGetDetailsAsync(),因为如果执行同步,它将在显示Data 之前引入显着延迟。我想尽快显示Data,然后让异步任务按照自己的节奏获取详细信息,然后让视图绑定赶上。

private async Task LongRunningGetDetailsAsync()
{
    foreach (MyType dataitem in this.Data)
    {
        dataitem.Details = await _apiEndpointService.GetDetails(dataitem.Id);
    }
}

LongRunningGetDetailsAsync() 是绑定未触发的位置。我在LongRunningGetDetailsAsync 的末尾设置了一个断点,观看 Data.Details - Data.Details 在那里,但它从未显示在视图中。

提前感谢您的宝贵时间!

编辑: 改为

public async Task OnDataRefreshed(ObservableCollection<MyType> data)
{
    this.Data = data;
    await LongRunningGetDetailsAsync();
} 
  • 仍然有同样的问题。 Data 绑定到 Mvx.MvxListView。如果列表很长并且某个项目碰巧不在视线范围内,则一旦滚动到它,它就会显示更新后的模型 OK。

“数据”:

    public class MyType
    {
        public string MyProperty { get; set; }
        public string Details { get; set; }
    }

    private ObservableCollection<MyType> _data;
    public ObservableCollection<MyType> Data
    {
        get { return _data; }
        set
        {
            if (SetProperty(ref _data, value))
            {
                RaisePropertyChanged(() => Data);
            }
        }
    }

视图绑定:

        <Mvx.MvxListView
        local:MvxBind="ItemsSource Data"
        local:MvxItemTemplate="@layout/listitem" 
        ... />

列表项:

       <TextView local:MvxBind="Text MyProperty" ...
       <TextView local:MvxBind="Text Details" ...

【问题讨论】:

  • 你使用的是INotifyPropertyChanged接口吗? Details 的属性怎么样?
  • @Default 细节是原始的 - 请参阅上面的编辑
  • 您需要在 PropertyChanged 更改时触发它。您能否在视图中添加如何绑定它?
  • @Default RaisePropertyChanged(() =&gt; Data); on set,查看 - 请参阅上面的补充
  • 是的,好吧,您需要在 Details 属性上使用它 - 这是一个变化。你的Data 没有(在电话Details = .. 中)。此外,尽量避免为您的收藏设置二传手。如果您需要添加新数据,请改用ClearAdd[Range]

标签: c# asynchronous xamarin mvvmcross


【解决方案1】:

首先,在调用函数时使用await 关键字并将函数标记为async

public async Task OnDataRefreshed(List<MyType> data)
{
    this.Data = data;
    await LongRunningGetDetailsAsync();
}

现在据我了解,您希望在获得每个项目后立即在 UI 中显示它们。如果您的绑定是正确的,那么上面的更改应该可以满足您的需求。不过,对于 Data 属性,您可能应该使用 ObservableCollection&lt;&gt; 而不是 List&lt;&gt;

【讨论】:

  • 感谢 Alireza。我确实将我的任务更改为 async/await LongRunning... 我的问题可能与MvxListView 以及它如何处理数据绑定有关。当列表项从视图中滚动出来,然后再返回时,这些值确实会按预期显示。如果列表太短并且没有滚动 - 没有 UI 更新。
  • 您是否将List&lt;&gt; 更改为ObservableCollection&lt;&gt;?您所描述的是人们在绑定到 List&lt;&gt; 而不是 ObservableCollection&lt;&gt; 时遇到的情况
  • 是的,我现在将我的列表设置为 ObservableCollection 无效。我的想法是这与模型更新是异步执行的事实有关。我尝试了几件事:RequestMainThreadActionInvokeOnMainThread 但这也无济于事。不知道从这里拿走它。 @Stuart @Martijn00 任何指针?
  • OP 正在更改 items 的属性,而不是列表本身。虽然我同意 ObservableCollection(或 ICollectionView)在这里更合适,但我怀疑它是否能解决 OPs 问题。
【解决方案2】:

由于您要更改 Details 属性,因此您需要让视图知道它已更改。您需要使用与 Data 属性相同的逻辑:

private string _details;
public string Details
{
    get { return _details; }
    set
    {
        if (SetProperty(ref _details, value))
        {
            RaisePropertyChanged(() => Details);
        }
    }
}

作为旁注,请尽量避免为您的列表设置二传手。将来,您可能会将其他逻辑连接到您的列表,这些逻辑在被覆盖时只会使事情复杂化。相反,由于它是作为 ObservableCollection&lt;T&gt; 公开的,因此您可以调用 Clear,然后在 getter 的值上调用 Add

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 2021-06-16
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    相关资源
    最近更新 更多