C# WPF:在.NET3.5中异步执行一些代码
我有一个MVVM WPF应用程序。我有一个窗口,比如说LvWindow,它有一个listview,它是从数据库的数据提交中加载的。从主窗口主窗口,我有一个菜单,其中有一些选项。当我选择访问LvWindow的选项时,它是打开的。然后,从ViewModel,在构造函数中,我调用了一个数据库,我从中请求一些数据,然后将这些数据加载到listview中 我的目标是使从数据库请求数据的过程,然后在listview中异步加载数据。我想这样做是为了不阻塞整个应用程序,我的意思是,在加载此窗口期间,用户可以转到主窗口菜单并选择打开另一种类型的窗口。窗口在选项卡中打开 在从数据库请求数据并加载到window LvWindow中的listview的过程中,我显示了一个提示:加载到itin上实际上这是一个zindex设置为更大数字的矩形,以避免用户在完全加载listview之前与listview交互。当listview加载来自数据库的数据时,此启动将关闭 因此,要使流程异步,我知道在winforms中,可以使用beginInvoke、endInvoke和回调方法通过委托完成,请参阅 另外,另一种可能是使用后台工作人员,如posted 那么在WPF中,哪种方法是最好的呢?将代理用作winforms或后台工作人员 尝试1: 我尝试过XANIMAX解决方案,如下所示:C# WPF:在.NET3.5中异步执行一些代码,c#,wpf,listview,asynchronous,delegates,C#,Wpf,Listview,Asynchronous,Delegates,我有一个MVVM WPF应用程序。我有一个窗口,比如说LvWindow,它有一个listview,它是从数据库的数据提交中加载的。从主窗口主窗口,我有一个菜单,其中有一些选项。当我选择访问LvWindow的选项时,它是打开的。然后,从ViewModel,在构造函数中,我调用了一个数据库,我从中请求一些数据,然后将这些数据加载到listview中 我的目标是使从数据库请求数据的过程,然后在listview中异步加载数据。我想这样做是为了不阻塞整个应用程序,我的意思是,在加载此窗口期间,用户可以转到
public class TestViewModel : BaseViewModel
{
private static Dispatcher _dispatcher;
public ObservableCollection<UserData> lstUsers
public ObservableCollection<UserData> LstUsers
{
get
{
return this.lstUsers;
}
private set
{
this.lstUsers= value;
OnPropertyChanged("LstUsers");
}
}
public TestViewModel()
{
ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
{
var result = getDataFromDatabase();
UIThread((p) => LstUsers = result);
}));
}
ObservableCollection<UserData> getDataFromDatabase()
{
return this.RequestDataToDatabase();
}
static void UIThread(Action<object> a)
{
if(_dispatcher == null) _dispatcher = Dispatcher.CurrentDispatcher;
//this is to make sure that the event is raised on the correct Thread
_dispatcher.Invoke(a); <---- HERE EXCEPTION IS THROWN
}
}
UserData是我的数据模型,它是一个具有一些公共属性的类。比如:
public class UserData
{
public string ID{ get; set; }
public string Name { get; set; }
public string Surname { get; set; }
// Other properties
}
因此,问题是对数据库的调用返回RequestDataToDatabase返回UserData ObservableCollection的集合,因此引发异常
我不知道如何解决它。你能帮帮我吗
最终解决方案:
正如XAMIMAX在评论中所说:
将签名从静态无效UIThreadAction a更改为静态无效UIThreadAction a
修改UIThreadp=>LstUsers=result;按UIThread=>LstUsers
=结果;
有两个选项可以异步运行该方法 异步等待- 任务并行库:
在C 7.0中,您不能等待构造函数中的异步方法,但在7.1中会出现async Main,因此在创建ViewModel并将其分配给视图的DataContext后,您可以提取对ViewModel中单独函数的异步函数调用,并在视图的代码隐藏构造函数中同步调用该函数:
public MainWindow()
{
this.vm = new MyViewModel();
this.DataContext = this.vm;
this.InitializeComponent();
this.vm.AsychronousFunctionToCallDatabase();
}
正如XAMIMAX所说,您希望实现一个ViewModel来处理视图和模型之间的业务逻辑。然后,如果您的ViewModel实现了INotifyPropertyChanged,并且您在XAML中设置了与ViewModel中的属性的绑定,那么在数据库调用之后,显示将刷新,而不会阻塞UI线程。注意,如果您有任何从数据库调用填充的集合,那么它们应该是ObservableCollection类型
但是正如Kundan所说,在AsychrousFunctiontoCallDatabase函数中,您应该在调用数据库的行中包含一个WAIT语句或create a Task,在这种情况下,这将把控制权返回给调用函数,返回给主窗口构造函数。以下是一种可能的解决方案。 在您的视图模型中,您将有如下内容:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace VM
{
public class TestViewModel : BaseViewModel
{
private static Dispatcher _dispatcher;
List<object> ListToDisplay { get; set; }//INPC omitted for brevity
public TestViewModel()
{
ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
{
var result = getDataFromDatabase();
UIThread(() => ListToDisplay = result);
}));
}
List<object> getDataFromDatabase()
{
//your logic here
return new List<object>();
}
static void UIThread(Action a)
{
if(_dispatcher == null) _dispatcher = Dispatcher.CurrentDispatcher;
//this is to make sure that the event is raised on the correct Thread
_dispatcher.Invoke(a);
}
}
}
你说的是MvvM,但从来没有提到过ViewModel。如果这是MvvM,尽管缺少视图模型,您可以使用。。。。在其构造函数中,我调用了一个非MVVM方式的数据库。@Filburt抱歉,我是说,viewmodel的构造函数。将签名从静态void UIThreadAction a更改为静态void UIThreadAction a。这将允许该方法按预期参数执行。@XAMlMAX最好发布另一个问题,我将在那里详细解释。我会回来并在这里的评论链接中发布。我已经实现了您的解决方案,但我得到了一个异常:TargetParameterCountException:参数计数不匹配。见我的帖子更新。问题在于,从数据库返回信息的方法返回的是用户数据的集合。您能告诉我如何解决这个问题吗?在NET3.5中,不支持任务。
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace VM
{
public class TestViewModel : BaseViewModel
{
private static Dispatcher _dispatcher;
List<object> ListToDisplay { get; set; }//INPC omitted for brevity
public TestViewModel()
{
ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
{
var result = getDataFromDatabase();
UIThread(() => ListToDisplay = result);
}));
}
List<object> getDataFromDatabase()
{
//your logic here
return new List<object>();
}
static void UIThread(Action a)
{
if(_dispatcher == null) _dispatcher = Dispatcher.CurrentDispatcher;
//this is to make sure that the event is raised on the correct Thread
_dispatcher.Invoke(a);
}
}
}