在开发Xamarin Forms应用时,经常会遇到需要在页面加载时执行异步操作的情况。然而,直接在构造函数中使用异步方法可能会导致问题。本文将介绍一种解决方案,该方案允许在页面加载后执行异步操作。
本文将从零开始,逐步介绍如何实现这一功能。将使用Visual Studio 2015 Community Edition和Xamarin for Visual Studio (4.1.1)版本进行开发。
创建项目并添加基础模型
首先,需要创建一个新的Xamarin Forms项目,并添加一个基础模型。这个模型将用于绑定数据和处理异步操作。以下是创建基础模型的步骤:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace AsyncTest.Models
{
internal abstract class BaseModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
为了处理异步操作,需要让基础模型知道它绑定到了哪个页面。因此,添加了一个CurrentPage属性:
protected Page CurrentPage { get; private set; }
接下来,需要一个初始化方法,用于设置CurrentPage属性并绑定页面的Appearing和Disappearing事件:
public void Initialize(Page page)
{
CurrentPage = page;
CurrentPage.Appearing += CurrentPageOnAppearing;
CurrentPage.Disappearing += CurrentPageOnDisappearing;
}
完整的基础模型代码如下:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace AsyncTest.Models
{
internal abstract class BaseModel : INotifyPropertyChanged
{
protected Page CurrentPage { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
public void Initialize(Page page)
{
CurrentPage = page;
CurrentPage.Appearing += CurrentPageOnAppearing;
CurrentPage.Disappearing += CurrentPageOnDisappearing;
}
protected virtual void CurrentPageOnAppearing(object sender, EventArgs eventArgs) { }
protected virtual void CurrentPageOnDisappearing(object sender, EventArgs eventArgs) { }
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
如所见,基础模型将页面作为属性,并为Appearing和Disappearing事件创建了虚拟方法。如果需要其他事件,只需将它们添加为虚拟方法即可。
创建页面并使用模型
已经拥有MainPage.xaml,现在将使用它。首先,需要为页面创建一个模型:
namespace AsyncTest.Models
{
internal class MainModel : BaseModel {}
}
将使用http://jsonplaceholder.typicode.com/进行测试。以下是MainModel的实现:
using System;
using System.Net.Http;
namespace AsyncTest.Models
{
internal class MainModel : BaseModel
{
private string _responseText;
public string ResponseText
{
get { return _responseText; }
set
{
_responseText = value;
OnPropertyChanged();
}
}
protected override async void CurrentPageOnAppearing(object sender, EventArgs eventArgs)
{
ResponseText = "Loading, please wait...";
try
{
// Wait for testing...
await Task.Delay(TimeSpan.FromSeconds(3));
using (var client = new HttpClient())
{
var responseMessage = await client.GetAsync("http://jsonplaceholder.typicode.com/posts/1");
if (responseMessage.IsSuccessStatusCode)
ResponseText = await responseMessage.Content.ReadAsStringAsync();
else
ResponseText = $"StatusCode: {responseMessage.StatusCode}";
}
}
catch (Exception exception)
{
ResponseText = exception.ToString();
}
}
}
}
喜欢设计器中的智能感知功能,所以将模型添加到设计器中:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:models="clr-namespace:AsyncTest.Models;assembly=AsyncTest" x:Class="AsyncTest.MainPage">
<ContentPage.BindingContext>
<models:MainModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<Label Text="{Binding ResponseText}" />
</ContentPage.Content>
</ContentPage>
using AsyncTest.Models;
namespace AsyncTest
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
((BaseModel) BindingContext).Initialize(this);
}
}
}