Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在viewmodel中调用异步方法_C#_Wpf_Asynchronous_Mvvm - Fatal编程技术网

C# 如何在viewmodel中调用异步方法

C# 如何在viewmodel中调用异步方法,c#,wpf,asynchronous,mvvm,C#,Wpf,Asynchronous,Mvvm,我正在尝试学习WPF应用程序中的MVVM模式。我在viewmodel中编写了这个异步方法,它必须是异步的,因为我使用的是HttpClient,并且它的方法是异步的: public async Task<Dictionary<int, BusStop>> GetBusStops() { var busStopDict = new Dictionary<int, BusStop>(); var url = "my url";

我正在尝试学习WPF应用程序中的MVVM模式。我在viewmodel中编写了这个异步方法,它必须是异步的,因为我使用的是HttpClient,并且它的方法是异步的:

public async Task<Dictionary<int, BusStop>> GetBusStops()
    {
        var busStopDict = new Dictionary<int, BusStop>();
        var url = "my url";

        using (HttpClient client = new HttpClient())
        using (HttpResponseMessage response = await client.GetAsync(url))
        using (HttpContent content = response.Content)
        {
            string data = await content.ReadAsStringAsync();
            var regularExpression = Regex.Match(data, "\\[(.)*\\]");
            var result = regularExpression.Groups[0];

            var json = JValue.Parse(result.ToString());
            var jsonArray = json.ToArray();

            foreach (var a in jsonArray)
            {
                // irrelevant logic

                busStopDict.Add(nr, bs);
            }
        }

        return busStopDict;
    }

此方法返回一个字典,其中包含我的模型中的公交站点。我想用视图中的combobox绑定这个字典,但我不能让它工作,因为我不能在viewmodel的构造函数中调用这个异步方法,我不知道在哪里可以调用它。您有什么建议吗?

我不建议在viewmodel构造函数中编写逻辑。相反,我会在视图中创建一个已加载的事件触发器,以确保不会干扰视图的加载过程

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"


<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>
然后在构造函数中分配它

LoadedCommand = new DelegateCommand(async () => await ExecuteLoadedCommandAsync());
添加加载的方法并在其中调用您的方法

private async Task ExecuteLoadedCommandAsync()
{
    var busStops = await GetBusStops();
    //TODO: display the busStops or do something else
}
此外,将Async作为后缀添加到asynchron方法名称中是一种很好的命名模式。它使您能够快速查看哪些方法是异步的。因此,将GetBusStops重命名为GetBusStopsAsync

这是一个简单的DelegateCommand实现

public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute) 
               : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute, 
               Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public override bool CanExecute(object parameter)
    {
        if (_canExecute == null)
        {
            return true;
        }

        return _canExecute(parameter);
    }

    public override void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        if( CanExecuteChanged != null )
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

我不建议在viewmodel构造函数中编写逻辑。相反,我会在视图中创建一个已加载的事件触发器,以确保不会干扰视图的加载过程

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"


<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>
然后在构造函数中分配它

LoadedCommand = new DelegateCommand(async () => await ExecuteLoadedCommandAsync());
添加加载的方法并在其中调用您的方法

private async Task ExecuteLoadedCommandAsync()
{
    var busStops = await GetBusStops();
    //TODO: display the busStops or do something else
}
此外,将Async作为后缀添加到asynchron方法名称中是一种很好的命名模式。它使您能够快速查看哪些方法是异步的。因此,将GetBusStops重命名为GetBusStopsAsync

这是一个简单的DelegateCommand实现

public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute) 
               : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute, 
               Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public override bool CanExecute(object parameter)
    {
        if (_canExecute == null)
        {
            return true;
        }

        return _canExecute(parameter);
    }

    public override void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        if( CanExecuteChanged != null )
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

在构造函数中启动异步方法,并定义一个类似的操作

//Constructor
public ViewModel()
{
    GetBusStops().ContinueWith((BusStops) =>
    {
        //This anonym method is called async after you got the BusStops
        //Do what ever you need with the BusStops
    });
}
如果要访问用于视图的属性,请不要忘记调用UI线程

Application.Current.Dispatcher.BeginInvoke(() =>
{
    //Your code here
});

在构造函数中启动异步方法,并定义一个类似的操作

//Constructor
public ViewModel()
{
    GetBusStops().ContinueWith((BusStops) =>
    {
        //This anonym method is called async after you got the BusStops
        //Do what ever you need with the BusStops
    });
}
如果要访问用于视图的属性,请不要忘记调用UI线程

Application.Current.Dispatcher.BeginInvoke(() =>
{
    //Your code here
});
我将签出AsycLazy或AsyncCommands,并创建一个基于异步任务的LoadCommand。您不应该在构造函数中加入太多的逻辑,因为这将使调试变得更加困难,迫使您进行强耦合,并使为视图模型编写单元测试变得非常困难。如果可以的话,我倾向于让一切都变得懒惰

异步懒惰

异步命令

我将签出AsycLazy或AsyncCommand,并创建一个基于异步任务的LoadCommand。您不应该在构造函数中加入太多的逻辑,因为这将使调试变得更加困难,迫使您进行强耦合,并使为视图模型编写单元测试变得非常困难。如果可以的话,我倾向于让一切都变得懒惰

异步懒惰

异步命令

你应该使用我有一整篇关于这个主题的文章

使用NotifyTask from,它可能如下所示:

public async Task<Dictionary<int, BusStop>> GetBusStopsAsync() { ... }
public NotifyTask<Dictionary<int, BusStop>> BusStops { get; }

MyViewModelConstructor()
{
  BusStops = NotifyTask.Create(() => GetBusStopsAsync());
}
然后,您的视图可以对BusStops.Result进行模型绑定,以获取字典或null(如果尚未检索),还可以对BusStops.IsNotCompleted/BusStops.IsFaulted进行数据绑定,以获取繁忙微调器/错误指示器。

您应该使用我有一篇关于此主题的完整文章

使用NotifyTask from,它可能如下所示:

public async Task<Dictionary<int, BusStop>> GetBusStopsAsync() { ... }
public NotifyTask<Dictionary<int, BusStop>> BusStops { get; }

MyViewModelConstructor()
{
  BusStops = NotifyTask.Create(() => GetBusStopsAsync());
}

然后,您的视图可以对BusStops.Result进行模型绑定。如果尚未检索,则可以获取字典或null,还可以对BusStops.IsNotCompleted/BusStops.IsFaulted进行数据绑定,以获取繁忙的微调器/错误指示器。

为什么您不能在构造函数中调用该方法?构造函数不能是异步的,因此我不能等待该方法。如果我不等待该方法,它将返回Task而不是Dictionary。基本上,您需要了解的所有信息都在本文中进行了详细描述:。我建议阅读它,而不是遵循下面的答案。为什么不能在构造函数中调用该方法?构造函数不能是异步的,所以我不能等待该方法。如果我不等待该方法,它将返回Task而不是Dictionary。基本上,您需要了解的所有信息都在本文中进行了详细描述:。我建议阅读它,而不是按照下面的答案。在viewmodel构造函数中编写代码是一种好的做法吗?这样也不会干扰视图的加载过程吗?您正在通过加载总线站初始化ViewModel。初始化通常在构造函数中完成。由于该方法仍然是异步的,因此不会影响视图的加载。因为ContinueWith没有在UI线程中运行,所以您可能必须使用调用,如我的回答中所示。但它是异步的,这是有原因的。它不应该更像LoadBusStopsAsync吗?这是一个拦网动作。这些不应该有不同的处理方式吗?我认为,在我的解决方案中,您不需要使用dispatcher。在这段代码中,您使用的是async方法。只有调用是在构造函数中完成的,因为您在初始化过程中需要它。我认为这取决于您的编码约定。我们不写任何逻辑

在构造函数中。我们只是将激活的服务分配给一个私有属性以供进一步使用,其他工作都已完成。在viewmodel构造函数中编写代码的好做法是什么?这样也不会干扰视图的加载过程吗?您正在通过加载总线站初始化ViewModel。初始化通常在构造函数中完成。由于该方法仍然是异步的,因此不会影响视图的加载。因为ContinueWith没有在UI线程中运行,所以您可能必须使用调用,如我的回答中所示。但它是异步的,这是有原因的。它不应该更像LoadBusStopsAsync吗?这是一个拦网动作。这些不应该有不同的处理方式吗?我认为,在我的解决方案中,您不需要使用dispatcher。在这段代码中,您使用的是async方法。只有调用是在构造函数中完成的,因为您在初始化过程中需要它。我认为这取决于您的编码约定。我们不在构造函数中编写任何逻辑。我们只需将激活的服务分配给私有财产以供进一步使用,其他任何工作都要完成。我需要在哪里自己实现DelegateCommand?如果是,如何使用?您可以使用经验证的可预测结果库实践。或者看一看更简单的实现值得注意的是,方法Execute和CanExecute不能被重写,因为它们不再是虚拟方法。该链接已有6年历史。我建议microsoft实现的是,我必须自己实现DelegateCommand吗?如果是,如何使用?您可以使用经验证的可预测结果库实践。或者看一个更简单的实现值得注意的是,方法Execute和CanExecute不能被重写,因为它们不再是虚拟方法。该链接已有6年历史。我建议microsoft实现