单身异步加载列表属性

时间:2017-01-11 18:07:56

标签: c# winforms asynchronous

我有一个winforms应用程序,其单例类包含一个属性(列表),它是搜索网格的数据源。填写此属性需要花费大量时间(> 1分钟),因此,我想在用户启动程序时异步地开始填充此属性。

主窗体有一个按钮来启动另一个搜索表单。如果,当用户启动搜索时,如果数据源已准备就绪,那么没问题。但是,如果数据源仍在填充,则用户会看到等待光标,并且一旦数据源完成填充,搜索网格填充。

为此,我创建了一个在异步方法完成后触发的方法,然后将网格绑定到数据源。

一切似乎都正常工作,事件触发,然后我尝试将列表绑定到网格,没有任何反应......调试暂停,我从未点击下一行代码(请参阅FrmSearch.cs中的注释)。

任何与错误或一般代码改进相关的想法都会非常明确,谢谢!

Program.cs的

static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Task.Run(async() => { Singleton.DogsList = await Dogs.FindAllAsync(); });

            Application.Run(new FrmMain());
        }
    }

Singleton.cs

public static class Singleton
    {
        public static event DogsListHandler DogsListLoaded;
        public delegate void DogsListHandler(object sender, EventArgs e);

        public static BindingList<Dogs> DogsList
        {
            get
            {
                if (dogsList == null)
                {
                    Task.Run(async () => 
                    {
                        dogsList = await Dogs.FindAllAsync();
                        notifyListLoaded();
                    });
                }
                return dogsList;
            }
            set { dogsList = value; }
        }
        private static BindingList<Dogs> dogsList;
        private static void notifyListLoaded()
        {
            if (DogsListLoaded != null) { DogsListLoaded(null, EventArgs.Empty); }
        }
    }

FrmSearch.cs

public partial class FrmSearch : Form //launched using the .Show() method from a button on the main form
{
    public FrmSearch()
    {
        InitializeComponent();
    }

    private void FrmSearch_Load(object sender, EventArgs e)
    {
        Singleton.DogsListLoaded += new Singleton.DogsListHandler(Dogs_ListLoaded);

        Cursor = Cursors.WaitCursor;
        if (Singleton.DogsList != null)
        {
            grid.DataSource = Singleton.DogsList;
            Cursor = Cursors.Default;
        }
        else { Cursor = Cursors.WaitCursor; }
    }

    public void Dogs_ListLoaded(object sender, EventArgs e)
    {
        grid.DataSource = Singleton.DogsList; //freezes here
        Cursor = Cursors.Default; //this line never gets hit
    }
}

Dogs.cs(将从db正常拉出,但只是对样本进行一些迭代)

public class Dogs
    {
        public string Name { get; set; }
        public string Breed { get; set; }
        public int Age { get; set; }
        public string Summary { get { return string.Format("Name: {0} / Breed: {1} / Age: {2}", Name, Breed, Age.ToString()); } }

        public static async Task<BindingList<Dogs>> FindAllAsync()
        {
            BindingList<Dogs> dl = new BindingList<Dogs>();

            await Task.Run(() =>
            {
                int i = 0;
                while (i <= 999999)
                {
                    dl.Add(new Dogs() { Name = "River" + i.ToString(), Breed = "Border Collie", Age = 3 });
                    dl.Add(new Dogs() { Name = "Jack" + i.ToString(), Breed = "Labrador", Age = 2 });
                    dl.Add(new Dogs() { Name = "Emma" + i.ToString(), Breed = "Beagle", Age = 7 });
                i++;
                }               
            });
            return dl;
        } 
    }

1 个答案:

答案 0 :(得分:0)

您应该检索列表,因为您将检索从任何地方获取的所有其他列表:

调用异步方法并等待它。

易于处理

public static class SomeLookups
{
    private static object _lock = new object( );
    private static Task<IList<string>> _foosAsync;

    public static Task<IList<string>> GetFoosAsync()
    {
        lock ( _lock )
        {
            return _foosAsync = _foosAsync ?? PrivateGetFoosAsync( );
        }
    }

    private static async Task<IList<string>> PrivateGetFoosAsync()
    {
        var list = new List<string>( );
        for ( int i = 0; i < 20; i++ )
        {
            await Task.Delay( 200 ).ConfigureAwait( false );
            list.Add( "item " + i );
        }
        return list.AsReadOnly( );
    }
}

在消费类

private async Task RetrieveAllData()
{
    IsBusy = true;
    MyFooCollection = await SomeLookups.GetFoosAsync();
    IsBusy = false;
}

任务完成后,您仍然可以等待它。但是因为它已经完成,你可以毫不拖延地得到结果。