【发布时间】:2015-09-22 03:26:46
【问题描述】:
我是 Xamarin Forms 的新手,并且有一个异步获取事务的应用程序,但是当我调用 Web 服务时它遇到了死锁。
我有一个 TransactionView:
这是 XAML:
<Label Text="Account:" Grid.Row="0" Grid.Column="0" Style="{StaticResource LabelStyle}"/>
<ctrls:BindablePicker x:Name="ddlAccountsWinPhone" ItemsSource="{Binding Accounts}" SelectedIndex="{Binding AccountID}" Grid.Row="0" Grid.Column="1" />
<Label Text="From Date:" Grid.Row="2" Grid.Column="0" Style="{StaticResource LabelStyle}"/> <DatePicker x:Name="dtFromWinPhone" Date="{Binding FromDate}" Grid.Row="2" Grid.Column="1" />
<Label Text="To Date:" Grid.Row="3" Grid.Column="0" Style="{StaticResource LabelStyle}"/> <DatePicker x:Name="dtToWinPhone" Date="{Binding ToDate}" Grid.Row="3" Grid.Column="1" />
<Button x:Name="btnViewWinPhone" Text="View" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Command ="{Binding ShowTransactions}" />
这是 TransactionView 背后的代码,注意我将在名为 TransactionSubPageView 的子页面上显示一个交易网格:
public partial class TransactionView : ContentPage
{
private TransactionViewModel transactionViewModel;
private TransactionViewModel ViewModel
{
get {
if (transactionViewModel == null) transactionViewModel = new TransactionViewModel(
this.Navigation, new TransactionSubPageView()); //Pass sub page to ViewModel ctor
return transactionViewModel;
}
}
public TransactionView()
{
InitializeComponent();
BindingContext = ViewModel;
}
这是 TransactionViewModel:
public class TransactionViewModel : ViewModelBase
{
private int accountID;
private List<Account> accounts = new List<Account>();
private Account accountItemSelected;
private DateTime fromDate = new DateTime(1900,1,1);
private DateTime toDate = new DateTime(1900, 1, 1);
private ContentPage transactionGridViewNav;
public TransactionViewModel(INavigation navigationInterface, ContentPage transactionSubPageView)
{
base.navigation = navigationInterface;
transactionSubPageViewNav = transactionSubPageView; //I SAVE A REFERENCE TO THE SUBPAGE HERE
accounts.AddRange(Client.Accounts);
}
public ICommand ShowTransactions
{
get
{
return new Command(async () =>
{
//HERE IS WHERE "I THINK" I WANT TO FETCH THE TRANSACTIONS
//THEN NAVIGATE TO THE THE SUBPAGE WITH THE GRID OF TRANSACTIONS
await navigation.PushAsync(transactionSubPageViewNav);
});
}
}
public int AccountID
{
get{ return this.accountID; }
set{
this.accountID = value;
this.OnPropertyChanged("AccountID");
}
}
public List<Account> Accounts
{
get{
return this.accounts;}
set{
this.accounts = value;
this.OnPropertyChanged("Accounts");
}
}
public Account AccountItemSelected
{
get{return accountItemSelected;}
set {
if (accountItemSelected != value)
{
accountItemSelected = value;
OnPropertyChanged("AccountItemSelected");
}
}
}
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }}
...
这是 TransactionSubPageView:
public partial class TransactionSubPageView : ContentPage
{
public TransactionSubPageViewModel transactionSubPageViewModel;
public TransactionSubPageViewModel ViewModel
{
get
{
if (transactionSubPageViewModel == null)
transactionSubPageViewModel = new TransactionSubPageViewModel();
return transactionGridViewModel;
}
}
private Grid gridTransactions;
public TransactionSubPageView()
{
InitializeComponent();
BindingContext = ViewModel;
}
protected async override void OnAppearing()
{
base.OnAppearing();
//THIS IS A VOID TO POPULATE A GRID AND SET THE PAGE'S CONTENT, IT USES
//transactionSubPageViewModel.TransactionsGrid!!
PopulateGridTransactions();
}
这是子页面视图模型:
public class TransactionSubPageViewModel : ViewModelBase
{
public List<Transaction> transactionsGrid = new List<Transaction>();
public int accountId = 1636;
public DateTime fromDate = new DateTime(2015, 8, 1);
public DateTime toDate = new DateTime(2015, 9, 1);
public TransactionGridViewModel() { }
public List<Transaction> TransactionsGrid
{
get {
if (transactionsGrid == null) transactionsGrid = MyWebService.GetTransactions(1636, new DateTime(2015, 8, 1), new DateTime(2015, 9, 1)).Result;
return transactionsGrid;}
}
}
最后是导致问题的 WebService 调用:
public static async Task<List<Transaction>> GetTransactions(int accountId, DateTime fromDate, DateTime toDate)
{
var client = new System.Net.Http.HttpClient(new NativeMessageHandler());
client.BaseAddress = new Uri("http://theWebAddress.com/);
var response = await client.GetAsync("API.svc/Transactions/" + accountId + "/" + fromDate.ToString("yyyy-MM-dd") + "/" + toDate.ToString("yyyy-MM-dd")); //.ConfigureAwait(false);
var transactionJson = response.Content.ReadAsStringAsync().Result;
var transactions = JsonConvert.DeserializeObject<List<Transaction>>(transactionJson);
return transactions;
}
感谢到目前为止的阅读,问题是 webmethod 调用中的这一行总是挂起:
var response = await client.GetAsync("API.svc/Transactions/" + accountId + "/" + fromDate.ToString("yyyy-MM-dd") + "/" + toDate.ToString("yyyy-MM-dd"));
如果我从子页面的OnAppearing 事件调用GetTransactions web 服务,它会挂起,如果我从ICommand ShowTransactions 调用它,它也会挂起。我错过了await 还是continue?
我有read 和fair 几个documents 和similar 人和who are confused,我知道我是encountering a deadlock,但我只是不知道如何解决它。
我试过ConfigureAwait(false) 没有运气。如果我可以在页面中的 background thread, show a progress bar and when the operation is complete render the results 上调用 WebService,那就太理想了。
【问题讨论】:
标签: c# xamarin async-await deadlock xamarin.forms