WinRT 8.1 异步数据绑定不更新 UI



我的问题与我读过的其他一些问题相似,但我无法找到我具体问题的答案。

注意:在提问之前,我已经阅读了以下问题:

Windows 8.1 应用商店应用的列表视图数据绑定

WinRT ViewModel DataBind to async Method

话虽如此,我正在创建一个 Windows 8.1 应用程序,该应用程序异步加载文本文件,并将数据绑定到ListBox。 我确定该问题与非 UI 线程无法更新 UI 有关,因此即使我的数据源实现了 INotifyPropertyChanged,加载数据时 UI 也不会更新。 这是我LoadPayees()方法:

public async void LoadPayees()
{
    try
    {
        var json = await FileService.ReadFromFile("folder", "payees.json");
        IList<Payee> payeesFromJson = JsonConvert.DeserializeObject<List<Payee>>(json);
        var payees = new ObservableCollection<Payee>(payeesFromJson);
        _payees = payees;
    }
    catch (Exception)
    {     
        throw;
    }
    if (_payees == null)
    {
        _payees = new ObservableCollection<Payee>();
    }
}

LoadPayees()在我的页面的OnNavigatedTo()事件中调用。 我可以通过断点看到该方法正在被调用,并且收款人正在加载到ObservableCollection<Payee>中。 _payees是一个属性,它在设置时调用OnPropertyChanged()

我的问题是,有没有办法在LoadPayees()完成加载数据后更新 UI 线程? 我还在某处读到使用Task对 UI 也没有好处。 我的静态方法FileService.ReadFromFile()返回一个Task<string>

编辑:

这是我的方法ReadFromFile()它也调用OpenFile()

public static async Task<string> ReadFromFile(string subFolderName, string fileName)
{
    SetupFolder();
    var file = await OpenFile(subFolderName, fileName);
    var fileContents = string.Empty;
    if (file != null)
    {
        fileContents = await FileIO.ReadTextAsync(file);
    }
    return fileContents;
}
public static async Task<StorageFile> OpenFile(string subFolderName, string fileName)
{
    if (_currentFolder != null)
    {
        var folder = await _currentFolder.CreateFolderAsync(subFolderName, CreationCollisionOption.OpenIfExists);
        return await folder.GetFileAsync(fileName);
    }
    else
    {
        return null;
    }
}

编辑 2:

下面是根据请求的属性、ViewOnNavigatedTo()的代码。

--

视图模型的属性 --

private ObservableCollection<Payee> _payees;
private Payee _currentPayee;
public PayeesViewModel()
{
    _currentPayee = new Payee();
    _payees = new ObservableCollection<Payee>();
}
public ObservableCollection<Payee> Payees
{
    get { return _payees; }
    set
    {
        _payees = value;
        OnPropertyChanged();
    }
}
public Payee CurrentPayee
{
    get { return _currentPayee; }
    set
    {
        _currentPayee = value;
        OnPropertyChanged();
    }
}

--视图--

<StackPanel Orientation="Horizontal"
            DataContext="{Binding Path=CurrentPayee}"
            Grid.Row="1">
    <Grid>
        <!-- snip unrelated Grid code -->
    </Grid>
    <ListBox x:Name="PayeesListBox"
             Margin="50,0,50,0"
             Width="300"
             ItemsSource="{Binding Path=Payees}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=CompanyName}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>
--

代码隐藏 --

private PayeesViewModel _vm = new PayeesViewModel();
public PayeesPage()
{
    this.InitializeComponent();
    this._navigationHelper = new NavigationHelper(this);
    this._navigationHelper.LoadState += navigationHelper_LoadState;
    this._navigationHelper.SaveState += navigationHelper_SaveState;
    DataContext = _vm;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    _navigationHelper.OnNavigatedTo(e);
    _vm.LoadPayees();
}

我认为问题是你设置了两次DataContext

<StackPanel Orientation="Horizontal"
            DataContext="{Binding Path=CurrentPayee}"
            Grid.Row="1">

DataContext = _vm;

ListBox是来自DataContext CurrentPayee的外部StackPanel的孩子。在当前收款人上,您没有收款人。不应多次设置 DataContext。

顺便说一句,像下面这样更改您的代码:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    _navigationHelper.OnNavigatedTo(e);
    await _vm.LoadPayees();
}
public async Task LoadPayees()
{
    try
    {
        var json = await FileService.ReadFromFile("folder", "payees.json");
        IList<Payee> payeesFromJson = JsonConvert.DeserializeObject<List<Payee>>(json);
        var payees = new ObservableCollection<Payee>(payeesFromJson);
        _payees = payees;
    }
    catch (Exception)
    {     
        throw;
    }
    if (_payees == null)
    {
        _payees = new ObservableCollection<Payee>();
    }
}

切勿为除事件处理程序以外的方法编写异步 void。

编辑:

更改视图模型中的可观察集合。您不应该为列表设置公共资源库。

private readonly ObservableCollection<Payee> _payees = new ObservableCollection<Payee>();
public ObservableCollection<Payee> Payees
{
    get { return _payees; }
}

比循环并将项添加到集合中。现在,视图已收到通知。

foreach (var item in payeesFromJson)
{
    Payees.Add(item);
}

最新更新