0

我想实现一个异步显示加载数据的控件。

到目前为止,我已经尝试过async awaityield。使用异步等待,在收集绑定数据时 UI 是可用的。

使用yield时,UI 将被阻止,直到数据被收集并绑定到控件。

是否可以结合yieldasync/wait的真实行为?

谢谢

这是代码:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WPFComponents
{
    /// <summary>
    /// Interaction logic for WindowAsync.xaml
    /// </summary>
    public partial class WindowAsync
    {
        public WindowAsync()
        {
            InitializeComponent();
        }

        private async void OnWindowLoad(object sender, RoutedEventArgs e)
        {
            ItemListView.ItemsSource = await GetItemsAsync();
            //ItemListView.ItemsSource = GetItems();
        }

        private async Task<ObservableCollection<string>> GetItemsAsync()
        {
            return await Task.Run(() =>
                {
                    ObservableCollection<string> collection = new ObservableCollection<string>();

                    for (int i = 0; i < 10; i++)
                    {
                        string item = string.Format("Current string from {0}.", i);
                        collection.Add(item);
                        Thread.Sleep(500);
                    }
                    return collection;
                });
        }

        private IEnumerable<string> GetItems()
        {
            for (int i = 0; i < 10; i++)
            {
                string item = string.Format("Current string from {0}.", i);
                Thread.Sleep(500);
                yield return item;
            }
        }
    }
}

这是 XAML:

<Window x:Class="WPFComponents.WindowAsync"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WindowAsync" Height="300" Width="300" Loaded="OnWindowLoad">
    <Grid>
        <ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" x:Name="ItemListView"
                      SelectionMode="Multiple" UseLayoutRounding="True"
                      IsSynchronizedWithCurrentItem="True" Margin="0,4,4,4"
                      BorderThickness="0"
                      HorizontalContentAlignment="Center"
                      VerticalContentAlignment="Top">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" VerticalAlignment="Top" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListView>

    </Grid>
</Window>
4

1 回答 1

3

是否可以结合 yield 和 async/wait 的真实行为?

await返回完整的结果,但您可以使用 TAP 中内置的进度报告。

我在这里写了一篇关于它的文章:C# 5 async 中的进度报告模式


所以你会做这样的事情:

private void OnWindowLoad(object sender, RoutedEventArgs e)
{
  var collection = new ObservableCollection<string>();
  ItemListView.ItemsSource = collection;

  var progress = new Progress<string>();
  progress.ProgressChanged += ( s, item ) =>
    {
      collection.Add( item ); // will be raised on the UI thread
    }
  ;

  Task.Run( () => GetItemsAndReport( progress ) );
}

void GetItemsAndReport( IProgress<string> progress )
{
    foreach ( var item in GetItems() ) progress.Report( item );
}

private IEnumerable<string> GetItems()
{
    for (int i = 0; i < 10; i++)
    {
        string item = string.Format("Current string from {0}.", i);
        Thread.Sleep(500);
        yield return item;
    }
}
于 2013-04-10T11:14:20.073 回答