C# WPF:在.NET3.5中异步执行一些代码

C# WPF:在.NET3.5中异步执行一些代码,c#,wpf,listview,asynchronous,delegates,C#,Wpf,Listview,Asynchronous,Delegates,我有一个MVVM WPF应用程序。我有一个窗口,比如说LvWindow,它有一个listview,它是从数据库的数据提交中加载的。从主窗口主窗口,我有一个菜单,其中有一些选项。当我选择访问LvWindow的选项时,它是打开的。然后,从ViewModel,在构造函数中,我调用了一个数据库,我从中请求一些数据,然后将这些数据加载到listview中 我的目标是使从数据库请求数据的过程,然后在listview中异步加载数据。我想这样做是为了不阻塞整个应用程序,我的意思是,在加载此窗口期间,用户可以转到

我有一个MVVM WPF应用程序。我有一个窗口,比如说LvWindow,它有一个listview,它是从数据库的数据提交中加载的。从主窗口主窗口,我有一个菜单,其中有一些选项。当我选择访问LvWindow的选项时,它是打开的。然后,从ViewModel,在构造函数中,我调用了一个数据库,我从中请求一些数据,然后将这些数据加载到listview中

我的目标是使从数据库请求数据的过程,然后在listview中异步加载数据。我想这样做是为了不阻塞整个应用程序,我的意思是,在加载此窗口期间,用户可以转到主窗口菜单并选择打开另一种类型的窗口。窗口在选项卡中打开

在从数据库请求数据并加载到window LvWindow中的listview的过程中,我显示了一个提示:加载到itin上实际上这是一个zindex设置为更大数字的矩形,以避免用户在完全加载listview之前与listview交互。当listview加载来自数据库的数据时,此启动将关闭

因此,要使流程异步,我知道在winforms中,可以使用beginInvoke、endInvoke和回调方法通过委托完成,请参阅

另外,另一种可能是使用后台工作人员,如posted

那么在WPF中,哪种方法是最好的呢?将代理用作winforms或后台工作人员

尝试1: 我尝试过XANIMAX解决方案,如下所示:

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);
        }
    }
}