【问题标题】:Populating Observable collection into List view from Async method从 Async 方法将 Observable 集合填充到 List 视图中
【发布时间】:2018-08-29 15:34:42
【问题描述】:

我有一个列表,我使用 for 循环的方法填充列表。只是一个从 1 到 10 的数字。然后我创建了一个列表视图并通过将我从方法获得的列表转换为可观察集合来填充它。在执行这个程序时,我可以看到填充有数字的列表视图。 但是当我使用异步方法填充相同的列表时,我看不到列表视图被填充。我使用断点来检查方法是否有效。但是这些方法都运行良好。甚至我的可观察集合也会被填充。但我看不到列表视图。

这是我的程序:

<Page
    x:Class="UWPListView.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWPListView"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility  /2006"
    xmlns:data="using:UWPListView.Models"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel>
            <ProgressRing IsActive="True" Width="50" Height="50"
                          Foreground="Red" Name="MyProgress"/>
            <TextBlock Text="ListItems" FontSize="30"/>
        </StackPanel>

        <ListView Grid.Row="1" ItemsSource="{x:Bind ListItems}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="data:ListItem">
                <TextBlock Text="{x:Bind Number}" VerticalAlignment="Center"Margin="10,0,0,0" Foreground="Red"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid> 
</Page>

Mainpage.xaml.cs

namespace UWPListView
{
    public sealed partial class MainPage : Page
    {
        private ObservableCollection<ListItem> ListItems;

        public MainPage()
        {
            this.InitializeComponent();
            ThisMethod().GetAwaiter();
        }

        private async Task ThisMethod()
        {
            MyProgress.Visibility = Visibility.Visible;
            ObservableCollection<ListItem> items = new ObservableCollection<ListItem>(await ListManager.GetItemsAsync());
            ListItems = items;
            MyProgress.Visibility = Visibility.Collapsed;
        }
    }
}

我的班级

namespace UWPListView.Models
{
    public class ListItem
    {
        public float Number { get; set; }
    }

    public class ListManager
    {
        public async static Task<List<ListItem>> GetItemsAsync()
        {
            var listItems = new List<ListItem>();
            Rootobject temperatures = await getTemperatureAsync();

            for (int i = 0; i < 3; i++)
            {
                listItems.Add(new ListItem() { Number = temperatures.hourly.data[i].temperature });
            }
            return listItems;
        }

        private async static Task<Rootobject> getTemperatureAsync()
        {
            HttpClient client = new HttpClient();
            var jsonData = await client.GetStringAsync("https://api.darksky.net/forecast/apikey/13.08,80.27?units=si");
            var parsedData = JsonConvert.DeserializeObject<Rootobject>(jsonData);
            return parsedData;
        }
    }

我在 Models 文件夹下创建了这个类,我还包含了这个语句 xmlns:data="using:UWPListView.Models"使用 UWPListView.Models;

【问题讨论】:

    标签: c# .net uwp async-await observablecollection


    【解决方案1】:

    我建议在页面加载时创建一个事件处理程序

    类似:

    <Page
    ...
    Loaded="MainPage_OnLoaded">
    

    然后在您的代码隐藏中,您可以拥有:

    private async void MainPage_OnLoaded(object sender, RoutedEventArgs e)
    {
        await ThisMethod();
    }
    

    您可能还想离开构造函数来初始化成员。

    【讨论】:

      【解决方案2】:

      使用我在下面为您的课程提供的代码,我已经为您简化了一些事情。

      你不需要在构造函数中做GetAwaiter(),这会使事情复杂化。

      您还需要在构造函数中初始化 observableCollection

      public sealed partial class MainPage : Page
      {
          private ObservableCollection<ListItem> ListItems;
      
          public MainPage()
          {
              this.InitializeComponent();
              this.Loaded += MainPageLoaded; //if you dont want to use loaded method u can use OnnavigatedTo() override as well.
              ObservableCollection<ListItem> ListItems = new ObservableCollection<ListItem>();
          }
      
          private async void MainPageLoaded(object sender, RoutedEventArgs e)
          {
              await ThisMethod();
          }
      
          private async Task ThisMethod()
          {
              MyProgress.Visibility = Visibility.Visible;
              var items = await ListManager.GetItemsAsync();
              foreach(var item in items)
              {
                  ListItems.Add(item);
              }
              MyProgress.Visibility = Visibility.Collapsed;
          }
      }
      

      【讨论】:

      • 那么我的代码发生了什么。为什么使用 GetAwaiter() 没有更新列表视图?
      • @karthickbz getawaiter 在您想测试编译器时使用,不要在生产代码中使用它,并且您的列表视图没有得到更新,因为当您不在构造函数中初始化集合时,它仍然为空,并且因为您没有使用 OneWay 数据绑定,因此当您稍后初始化集合时,它会获取数据但它无法更新您的列表视图,因为您的数据绑定只是“OneTime”
      【解决方案3】:

      不要使用Task.GetAwaiter():

      此方法旨在供编译器使用,而不是在应用程序代码中使用。

      我会修改你的应用,让你等到页面加载完毕,然后再加载你的模型:

      namespace UWPListView
      {
          public sealed partial class MainPage : Page
          {
              public ObservableCollection<ListItem> Model; // change your XAML to bind to Model instead of ListItems
      
              public MainPage()
              {
                  this.InitializeComponent();
                  this.Loaded += new RoutedEventHandler(OnLoaded);
              }
      
              private async void OnLoaded(object sender, RoutedEventArgs e)
              {
                  MyProgress.Visibility = Visibility.Visible;
                  this.Model = await ListManager.GetItemsAsync();
                  MyProgress.Visibility = Visibility.Collapsed;
              } 
          }
      }
      

      请注意,事件处理程序是唯一应该使用async void 而不是async Task (reference) 的地方之一。

      【讨论】:

        猜你喜欢
        • 2014-01-05
        • 2017-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多