我有一个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;
}
}
答案 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;
}
任务完成后,您仍然可以等待它。但是因为它已经完成,你可以毫不拖延地得到结果。