C# 如何加载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

我正在尝试实现MVVM,并在ViewModel中执行一些异步数据获取。为此,我尝试在构造函数中加载数据:

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
return
Task
就可以了<代码>任务
异步的
等价于
无效的
;除非您正在编写事件处理程序,否则永远不要使用
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;