C# 如何加载viewmodel并仍然获取事件?
我正在尝试实现MVVM,并在ViewModel中执行一些异步数据获取。为此,我尝试在构造函数中加载数据:C# 如何加载viewmodel并仍然获取事件?,c#,windows-phone-8,async-await,C#,Windows Phone 8,Async Await,我正在尝试实现MVVM,并在ViewModel中执行一些异步数据获取。为此,我尝试在构造函数中加载数据: MyModel Model { get; set; } public MyViewModel() { Model = new MyModel(); Model.Foo = await LoadDataFromIsolatedStorage(); 但这是无效的,因为您不能将async附加到构造函数。所以我尝试了一个公共静态加载函数: MyModel Model { get; set
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
Model.Foo = await LoadDataFromIsolatedStorage();
但这是无效的,因为您不能将async附加到构造函数。所以我尝试了一个公共静态加载函数:
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
}
async public static void Load()
{
Model.Foo = await LoadDataFromIsolatedStorage();
但是这里WP8抱怨说它不能等待void。因为您需要设置ViewModel并将其绑定到视图的代码隐藏中的视图。没趣的
最后一个修复方法是使Load函数返回一个ViewModel,以便您在视图的代码隐藏中可以执行以下操作:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MyViewModel viewModel = await MyViewModel.Load();
要加载以下代码:
MyModel Model { get; set; }
public MyViewModel()
{
Model = new MyModel();
}
async public static Task<MyViewModel> Load()
{
MyViewModel viewModel = new MyViewModel();
viewModel.Model.Foo = await LoadDataFromIsolatedStorage();
return viewModel;
会起作用,但我“不能等待空虚”:
异步保护覆盖无效OnNavigatedTo(NavigationEventArgs e)
{
MyViewModel viewModel=新的MyViewModel();
viewModel.NavigationAction+=viewModel\u NavigationAction;
wait viewModel.Load();//给定的负载仅为异步void而不是任务
}
void viewmodel_导航操作(发送方,参数)
{
导航服务。导航(…)
}
roliu所写的内容非常有意义,因为异步/等待模式的整个概念都是基于任务的。在编写异步方法时,您始终需要返回一个任务,以确保下面的wait将起作用。通常编译器会在后台进行一些特殊的替换,因此您不必关心它
您永远不会因为异步操作而得到bool,而是一个通用bool类型的任务!确保您理解中描述的模式
然后你可以创建这样的东西。它不是Win8应用程序。为了简单起见,我选择它作为控制台应用程序
class Program
{
static void Main(string[] args)
{
DoWork();
}
static async void DoWork()
{
await YourVoidMethod();
}
static Task YourVoidMethod()
{
Task task = Task.Run(() =>
{
// Your payload code
}
);
return task;
}
}
作为提示:在使用GUI时,您还需要使用调度程序。更改UI线程的数据时,您可能会生成跨线程异常。我假设此代码块“不起作用”,因为加载数据后,事件设置得太晚:
MyViewModel viewModel = await MyViewModel.Load();
viewModel.NavigationAction += viewmodel_NavigationAction;
在这种情况下,修复最后一个代码块非常简单:让Load
returnTask
就可以了<代码>任务
是异步的
等价于无效的
;除非您正在编写事件处理程序,否则永远不要使用async void
。有关更多信息,请参阅我的文章
然而,即使当你开始工作时,在虚拟机加载之前,你也会得到一个空的视图;如果您的负载可能需要很长时间(或者如果没有网络连接,就会出现错误),那么这可能是一种糟糕的用户体验
<>你可能想考虑使用,我。该模式允许您(立即)创建处于“加载”状态的VM,该状态将(通过INotifyPropertyChanged
)转换为“加载”或“加载错误”状态。我认为,这种模式提供了更好的用户体验。仍在阅读这个问题,但您可以使用“async void”方法,只需将返回类型更改为Task
。一个简单的方法就是在加载时返回bool。我想说的是,您不需要进行任何攻击。我认为.NET允许您等待void
方法,但更喜欢使用Task
s。错误消息可能指的是loaddatafromsolatedstorage
的void
返回类型。不过我不太明白这个问题。如果加载的数据应该强制应用程序导航到另一个页面。。。为什么不在Load()
完成后导航到另一个页面呢?见鬼,如果这种重定向能够发生,为什么要使它异步呢?用户在使用UI时可能不想被重定向请看Stephen Cleary的文章。这个答案有几个问题:1)Main
不能async
2)您应该使用任务。运行而不是新任务
/任务。启动3)使用后台任务初始化viewmodel在许多情况下都不起作用,因为大多数VM都具有UI线程关联性。我对这个答案投了否决票,因为它包含一些糟糕的实践(例如Task.Start
,它与async
如何创建其任务无关),并且不适用于这个问题(因为它在后台线程上创建/初始化VM)。请注意,正确编写的async
UI应用程序不需要使用dispatcher。看起来您是对的。无法使异步Main()工作。我还修复了Task.Start()。你还有别的建议吗?直到今天,我才意识到Task.Factory.StartNew()在这种情况下的优势。谢谢:-)@Stephen:我真的很喜欢你关于Task.Run()与Task.Factory.StartNew()的讨论-我会把Task.Factory.StartNew()作为第一选择,因为在我的大多数Microsoft新闻书籍中,它被推荐为创建新线程的快速方法。但正如你所说的,这会让人困惑。
class Program
{
static void Main(string[] args)
{
DoWork();
}
static async void DoWork()
{
await YourVoidMethod();
}
static Task YourVoidMethod()
{
Task task = Task.Run(() =>
{
// Your payload code
}
);
return task;
}
}
MyViewModel viewModel = await MyViewModel.Load();
viewModel.NavigationAction += viewmodel_NavigationAction;