C# 我应该如何为应用程序设计类结构,以便异步更新UI
(免责声明:我是c#的新手,只是想弄清楚) 当从多个线程与UI交互时,是否有“最佳实践”?我看到一些人建议从每个数据加载器调用C# 我应该如何为应用程序设计类结构,以便异步更新UI,c#,wpf,C#,Wpf,(免责声明:我是c#的新手,只是想弄清楚) 当从多个线程与UI交互时,是否有“最佳实践”?我看到一些人建议从每个数据加载器调用Invoke,但其他人建议数据收集线程应该以某种方式通知UI线程,并依靠该线程适当地更新UI。我比较喜欢后者,所以在绘图线程中有一个共享的对象列表和一个循环来显示和删除列表中的任何对象会更好吗?或者我喜欢的另一个想法是使用包含控件(或顶级窗口)的方法,例如notifydonegateringuserlist(列表名和notifydonegateringuserdata(用
Invoke
,但其他人建议数据收集线程应该以某种方式通知UI线程,并依靠该线程适当地更新UI。我比较喜欢后者,所以在绘图线程中有一个共享的对象列表和一个循环来显示和删除列表中的任何对象会更好吗?或者我喜欢的另一个想法是使用包含控件(或顶级窗口)的方法,例如notifydonegateringuserlist(列表名和notifydonegateringuserdata(用户)
,因此收集线程不需要知道任何关于共享对象的想法;如果这是可行的,是否有System.Window.GetMainWindow()
风格的函数,或者每次生成一个像新线程(GetUserDataFromUser(user,this))
这样的收集线程时,我是否需要/想要传递对象
举例说明:
调用
public MainWindow()
{
new Thread(GetUsers());
public void GetUsers()
{
List<string> users;
<load users here>
mainWindow.Invoke((delegate){userList.Text = users.ToString()});
}
public主窗口()
{
新线程(GetUsers());
public void GetUsers()
{
列出用户名单;
调用((委托){userList.Text=users.ToString()});
}
共享对象
public MainWindow()
{
new Thread(GetUsers());
// somehow start a look to handle UI updates here without blocking...have to investigate.
}
private Loop()
{
while (true)
{
lock(sharedList);
if (!sharedList.empty())
{
userList.Text += sharedList.Front().ToString();
sharedList.PopFront();
}
sharedList.Unlock();
Sleep(50);
}
}
// data gathering class
public void GetUsers()
{
List<string> users;
<load users here>
lock(mainWindow.sharedList);
mainWindow.sharedList.Push(users)
unlock(mainWindow.sharedList);
}
public主窗口()
{
新线程(GetUsers());
//不知何故,在这里开始寻找在不阻塞的情况下处理UI更新的方法…必须进行调查。
}
专用循环()
{
while(true)
{
锁(共享列表);
如果(!sharedList.empty())
{
userList.Text+=sharedList.Front().ToString();
sharedList.PopFront();
}
sharedList.Unlock();
睡眠(50);
}
}
//数据收集类
public void GetUsers()
{
列出用户名单;
锁(主窗口.共享列表);
mainWindow.sharedList.Push(用户)
解锁(主窗口.共享列表);
}
公开方法
public MainWindow()
{
new Thread(GetUsers());
// somehow start a look to handle UI updates here without blocking...have to investigate.
}
private Loop()
{
while (true)
{
lock(sharedList);
if (!sharedList.empty())
{
userList.Text += sharedList.Front().ToString();
sharedList.PopFront();
}
sharedList.Unlock();
Sleep(50);
}
}
public void NotifyUsersLoaded(List<string> users)
{
lock(this.sharedList);
this.sharedList.Push(users)
unlock(thissharedList);
}
// data gathering class
public void GetUsers()
{
List<string> users;
<load users here>
mainWindow.NotifyUsersLoaded(users)
}
public主窗口()
{
新线程(GetUsers());
//不知何故,在这里开始寻找在不阻塞的情况下处理UI更新的方法…必须进行调查。
}
专用循环()
{
while(true)
{
锁(共享列表);
如果(!sharedList.empty())
{
userList.Text+=sharedList.Front().ToString();
sharedList.PopFront();
}
sharedList.Unlock();
睡眠(50);
}
}
public void NotifyUsersLoaded(列出用户)
{
锁(this.sharedList);
this.sharedList.Push(用户)
解锁(此共享列表);
}
//数据收集类
public void GetUsers()
{
列出用户名单;
mainWindow.NotifyUsersLoaded(用户)
}
在我个人看来,这要简单得多。你认为(通常)我们使用UI线程更新UI是正确的。至于获取数据和实现长时间运行的功能,我们真的不需要不断创建新线程,特别是新线程()
…在.NET中直接使用线程
类有点“过时”
使用带有回调处理程序的异步委托
s要容易得多,如果您使用的是.NET 4.5,则使用全新的wait
关键字更容易。如果您不知道这些,请查看以下链接:
当使用这些方法时,您不需要在工作完成时“通知”UI线程……或者您的代理有一个回调处理程序,或者您的方法只是在wait
关键字之后继续……非常简单
在编写异步WPF应用程序时,最后要注意的一点是,在UI中,您可能希望在数据绑定控件上将Binding
类的IsAsync
属性设置为True
。基本上,这只是避免在获取数据时阻塞UI。看看BackgroundWorker类,这允许使用同步的进程更新/完成事件进行异步处理,甚至异步/等待模式也可以适合您的场景,或者触发一个线程并通过触发另一个类中该线程中的自定义事件来处理更新-并将处理程序挂接到UI线程中的该自定义事件。是否有“最佳实践”
-是,它叫MVVM。如果你从WPF开始,请研究一下这个。它将大大简化你的代码和生活。我在研究中确实遇到了async/await关键字,但给出的示例似乎没有演示来自单个处理程序的多个异步事件。很接近,但这些都需要在一切都完成了。假设我在一个事件处理程序中连接了3个数据采集器-我首先在所有3个框中显示“加载…”,然后尝试加载所有3个(这里可能多线程更快?)。一旦完成任何操作,它会更新相应的控件。不过我会查看代理-谢谢!