我正在尝试找到一种将视图绑定到需要使用 <HttpPost()>
Function ReturnURL(FullURL As String) As ActionResult
Try
If FullURL.Contains("ReturnUrl") Then
Dim vID As Integer = FullURL.IndexOf("=")
Dim vSub As String = FullURL.Substring(vID + 1)
Session("ReturnUrl") = vSub.Replace("%2F", "/")
End If
Return Json("Success")
Catch ex As Exception
EmailError(ex, 53, PageName)
Return Json("Invalid")
End Try
End Function
方法填充的viewmodel属性的好方法。我最新得到的就是像这样使用IsAsync
。
ViewModel.cs
async
View.xaml
public class ViewModel
{
public Task<string> Name { get; set; }
public ViewModel()
{
Name = GetNameAsync();
}
public async Task<string> GetNameAsync()
{
return await Task.Run(async () =>
{
await Task.Delay(5000);
return "Foo";
});
}
}
这似乎可行,但是我不确定是否正在使用<Label Content="{Binding Name.Result, IsAsync=true}" />
,因为它应该被使用。 documentation没有声明与IsAsync
相关的任何内容,还有this comment on a stackoverflow说Task
与C#IsAsync
不相关。
这种实现有什么问题?
答案 0 :(得分:0)
处理这种“一次性”异步属性的最干净方法是使用Stephen Cleary的Nito.Asyncex库(在Nuget中提供)中的NotifyTaskCompletetion。
您的ViewModel随后将成为
async
然后您将作为标准绑定绑定到public class ViewModel
{
public INotifyTaskCompletion<string> Name { get; set; }
public ViewModel()
{
Name = NotifyTaskCompletetion.Complete(GetNameAsync());
}
private async Task<string> GetNameAsync()
{
return await Task.Run(async () =>
{
await Task.Delay(5000);
return "Foo";
});
}
}
,不需要IsAsync。
更多详细信息here。
答案 1 :(得分:0)
更正IsAsync选项与Task无关,它只是告诉UI显示回退值,而不会在get调用运行时阻塞。
您的代码可能出什么问题。嗯,我想如果有任何实际错误,我必须进行测试以解决问题。您有很多“坏”的事情。
构造函数中的代码。您可以保留任务引用,因此,它并不全是坏事,但通常,您不应在构造函数中使用像这样的代码
在任务上调用.Result。这可能会导致死锁
具有异步任务,但未等待它。
使用Task.Run在Task中运行?您可以直接调用await Task.Delay
我将按照以下方式重构您的代码
ViewModel
public class ViewModel : INotifyPropertyChanged
{
private string name
public string Name {
get {return name;}
set {
name = value;
PropertyChanged("Name");
}
public ICommand GetNameAsync;
private void PropertyChanged(string prop)
{
if( PropertyChanged != null )
{
PropertyChanged(this, new PropertyChangedEventArgs(prop);
}
}
public ViewModel()
{
Name="Loading...";
GetNameAsync = new AsyncCommand(async () => {Name = await GetNameAsync()});
}
private async Task<string> GetNameAsync()
{
await nameService.getName();
}
}
XAML
<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetNameAsync}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Label Content="{Binding Name}" />
</Window>
现在,当窗口加载时,您的Xaml将调用GetName函数,标签将显示“ Loading ...”,直到GetName函数完成,然后将其更新为Name
不幸的是
WPF没有AsyncCommand。
您必须自己制造,或使用第三方框架中的一个(见下文)
INotifyPropertyChanged令人讨厌输入。
我建议使用Fody及其INotifyPropertyChanged插件 https://github.com/Fody
AsyncCommand
https://mike-ward.net/2013/08/09/asynccommand-implementation-in-wpf/
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace OpenWeather.Command
{
internal class AsyncCommand : ICommand
{
private readonly Func<Task> _execute;
private readonly Func<bool> _canExecute;
private bool _isExecuting;
public AsyncCommand(Func<Task> execute) : this(execute, () => true)
{
}
public AsyncCommand(Func<Task> execute, Func<bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return !(_isExecuting && _canExecute());
}
public event EventHandler CanExecuteChanged;
public async void Execute(object parameter)
{
_isExecuting = true;
OnCanExecuteChanged();
try
{
await _execute();
}
finally
{
_isExecuting = false;
OnCanExecuteChanged();
}
}
protected virtual void OnCanExecuteChanged()
{
if (CanExecuteChanged != null) CanExecuteChanged(this, new EventArgs());
}
}
}