【发布时间】:2015-01-14 05:59:14
【问题描述】:
我的问题与我读过的其他一些问题相似,但我无法找到具体问题的答案。
注意: 在提问之前我已经阅读了以下问题:
ListView Data Binding for Windows 8.1 Store Apps
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:
这是属性的代码,View 和 OnNavigatedTo() 应要求提供。
-- ViewModel 的属性--
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();
}
【问题讨论】:
-
我正在学习 PluralSight 的一个名为“Windows 8 - 从设计到交付使用 C# 和 XAML”的教程。这些课程都是基于 Windows 8 构建的,因此不会反映 8.1 的特定更改。
-
这些代码 sn-ps 对我来说看起来不错。可以添加属性、视图和 OnNavigatedTo 代码吗?
-
当await返回时,无论工作在哪里完成,它都会返回到它被调用的线程上下文,这就是为什么您可以在调用并返回调用的等待方法之后实际更新UI元素用户界面线程。 LoadPayees() 被调用到 UI 线程,所以你应该没问题。我们需要查看 XAML 并正确设置页面的 DataContext,以便数据绑定正常工作。
-
我已经添加了属性、视图和 OnNavigatedTo() 代码。我剪掉的网格只是几个文本块/文本框,用于输入保存到收款人的数据。该部分工作正常,只是加载不起作用。
标签: c# asynchronous data-binding windows-runtime windows-8.1