我有一个MVVM WPF应用程序。我有一个窗口,让我们说" LvWindow",列表视图是从数据库中传入的数据加载的。从主窗口" MainWindow",我有一个菜单,有一些选项。当我选择访问" LvWindow"的选项时,它是打开的。然后从ViewModel,在构造函数中,我调用了一个数据库,我从中请求了一些数据,然后我加载到listview中。
我的目标是使进程从数据库请求数据,然后在listview中异步加载它。我想要这个是为了不阻止整个应用程序,我的意思是,在这个窗口加载时,用户可以转到主窗口菜单并选择打开另一种类型的窗口。 Windows在标签页中打开。
在从数据库请求数据并将其加载到窗口" LvWindow"中的列表视图的过程中,我展示了一个泼溅的说法"正在加载"在它上面(实际上这是一个矩形,zindex设置为更高的数字,以避免用户可以与listview交互,直到它被完全加载)。当列表视图加载来自数据库的数据时,将关闭此启动。
因此,要使进程异步,我知道在winforms中可以使用beginInvoke,endInvoke和callbacks方法完成委托,请参阅here。
另外,另一种可能性是使用后台工作人员,例如发布here。
那么在WPF中这是最好的方法吗?使用代表作为winforms或后台工作者?
ATTEMPT#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
}
}
但在行_dispatcher.Invoke(a)中抛出异常:
TargetParameterCountException: the parameter count mismatch
UserData是我的数据模型,它是一个具有一些公共属性的类。类似的东西:
public class UserData
{
public string ID{ get; set; }
public string Name { get; set; }
public string Surname { get; set; }
// Other properties
}
所以问题是对数据库的调用正在返回&#34; RequestDataToDatabase&#34;返回UserData(ObservableCollection)的集合,以便抛出异常。
我不知道如何解决它。请问你能帮帮我吗?
最终解决方案:
正如XAMIMAX在评论中所说:
答案 0 :(得分:1)
由于您无法在C#7.0中的构造函数中等待异步方法(但是异步Main将在7.1中出现),您可以将异步函数调用提取到ViewModel中的单独函数,并在View的代码隐藏中同步调用它构造函数,在您创建ViewModel并将其分配给View的DataContext之后:
public MainWindow()
{
this.vm = new MyViewModel();
this.DataContext = this.vm;
this.InitializeComponent();
this.vm.AsychronousFunctionToCallDatabase();
}
正如XAMIMAX所说,您希望实现ViewModel来处理View和模型之间的业务逻辑。然后,如果您的ViewModel实现了INotifyPropertyChanged,并且您在XAML中将Binding设置为ViewModel中的属性 - 那么在数据库调用之后,显示将刷新而不会阻止UI线程。注意,如果您从数据库调用中填充了任何集合,那么它们应该是ObservableCollection类型。
但正如Kundan所说,在你的AsychronousFunctionToCallDatabase()函数中,你应该在调用数据库的行上包含一个await语句或者创建一个Task - 这会将控制权返回给调用函数(在这种情况下,返回到MainWindow构造函数) )。
答案 1 :(得分:0)
有几种方法可以异步运行该方法。
答案 2 :(得分:0)
以下是您可能采用的解决方案之一 在您的视图模型中,您将拥有以下内容:
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);
}
}
}