【发布时间】:2017-01-11 18:07:55
【问题描述】:
我有一个带有单例类的 winforms 应用程序,其中包含一个属性(列表),该属性是搜索网格的数据源。填充此属性需要大量时间(> 1 分钟),因此,我想在用户启动程序时开始异步填充此属性。
主表单有一个按钮来启动另一个搜索表单。如果,当用户启动搜索时,如果数据源已准备好,那么没问题。但是,如果数据源仍在填充,用户会看到等待光标,并且搜索网格应该在数据源完成填充后立即填充。
为此,我创建了一个在异步方法完成后触发的方法,然后将网格绑定到数据源。
一切似乎都正常工作,事件触发,然后我尝试将列表绑定到网格,但没有任何反应...调试停止,我从未点击下一行代码(请参阅 FrmSearch.cs 中的 cmets)。
任何与问题或一般代码改进有关的想法都将非常受欢迎,谢谢!
程序.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(通常会从数据库中提取,但只是对样本进行一些迭代)
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;
}
}
【问题讨论】:
-
aync 属性... 似乎是个坏主意。如果您需要深入研究数据库,它应该是一种方法。你不能等待一个属性,因为你只能等待一个
Task或Task<T>。你需要做一些重新设计!你甚至不使用线程安全集合。 -
嗨,彼得,我在上面添加了 dogs.cs 类。在我的真实应用程序中,是的,这确实是从数据库中提取的,但是对于 dogs.cs 示例,我只是在进行一些迭代。 dog 类确实返回了一个 Task
>。我是异步的新手。对重新设计有什么建议吗? -
您应该查看
NotifyTaskCompletion,它是为处理异步绑定而设计的,就像您尝试做的那样。这是GitHub page for the most updated version。
标签: c# winforms asynchronous