動的にXamarin.FormsのXAMLファイルをロードするときのライブラリとして使っている、Xamarin.Forms.XamlProvilder を NuGet で公開しました。
NuGet Gallery | Xamrin.Forms Xaml Provider 0.1.1
https://www.nuget.org/packages/Xamarin.Forms.XamlProvider/0.1.1
XAMLの文字列から ContentPage 等を作るので、こんな風にXAML形式のデータをC#のコード内に埋め込んで記述ができます。
public void LoadSample()
{
string xml = @"<?xml version='1.0' encoding='utf-8' ?>
<ContentPage xmlns='http://xamarin.com/schemas/2014/forms'
xmlns:x='http://schemas.microsoft.com/winfx/2009/xaml'
x:Class='XFormsPreview.NewPage'>
<StackLayout>
<Label Text='New Page' />
<Button Text='Click me' />
</StackLayout>
</ContentPage>";
var page = PageXaml.LoadXaml<ContentPage>(xml);
Assert.IsNotNull(page);
var layout = page.Content as StackLayout;
Assert.IsNotNull(layout);
Assert.AreEqual(2, layout.Children.Count);
文字列から動的に変換するので、ファイルリソースをプロジェクトに埋め込ませて読み込むこともできます。
[TestMethod]
public void GridDemoPage()
{
var fs = File.OpenText(@"XamlGridDemoPage.xaml");
var xaml = fs.ReadToEnd();
var page = PageXaml.LoadXaml<ContentPage>(xaml);
Assert.IsNotNull(page);
Assert.AreEqual("Grid Demo Page", page.Title );
Assert.AreEqual(new Thickness(0, 20, 0, 0), page.Padding);
これを HTTP 経由で拾ってくるようにしたのが XFormsPreviewer です。
async void OnClickSample0(object sender, EventArgs e)
{
var hc = new HttpClient();
try
{
var res = await hc.GetStringAsync("http://localhost:10150/get/0");
var page = PageXaml.LoadXaml(res);
await this.Navigation.PushAsync(page);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
当然、HTTP 経由で拾ってくるので、インターネット上に XAML ファイルを配置しておけば、アプリケーションの更新なしに、動的に Xamarin製 XAML ファイルをダウンロードして表示を変えることが可能です…が、いまのところ、プレビューの機能しかないので静的ページしか表示できません。この部分はちょうど Javascript 無しの WebView みたいなものです。
■名前を取得する
ver.0.1.1 では、x:Name で Element を参照できるようにしました。
public void TestName()
{
string xml = @"<?xml version='1.0' encoding='utf-8' ?>
<ContentPage xmlns='http://xamarin.com/schemas/2014/forms'
xmlns:x='http://schemas.microsoft.com/winfx/2009/xaml'
x:Class='XFormsPreview.NewPage'>
<StackLayout>
<Label x:Name='label1' Text='New Page' />
<Button x:Name='button1' Text='Click me' />
</StackLayout>
</ContentPage>
";
var page = PageXaml.LoadXaml<ContentPage>(xml);
Assert.IsNotNull(page);
var layout = page.Content as StackLayout;
var label1 = page.FindByName<Label>("label1");
var button1 = page.FindByName<Button>("button1");
Assert.IsNotNull( label1 );
Assert.AreEqual("New Page", label1.Text);
Assert.AreEqual("Click me", button1.Text);
}
XAML内に x:Name で名前を付けておくと、Xamarin.Forms や WPFなどでは、それぞれのプロパティにしてくれますが、動的にXAMLファイルをロードする場合は直接プロパティを参照しづらいので、FindByName<Label>(“name”) のように参照します。FindByName 自体は Xamarin.Forms にもあるし、Silverlight でよく使うパターンです。
こうすると、固定で Xamarin.Forms を作ったときと同じように、各種のプロパティが設定できます。
var page = PageXaml.LoadXaml<ContentPage>(xml); var label1 = page.FindByName<Label>("label1"); label1.Text = "change display";
■BindingContent を実装中
ただし、x:Name でコントロールのオブジェクトを取ってくると、動的にロードされた XAML との接点が多くなってしまうので、もっと沿結合にするため BindingContext の部分を実装中です。MVVM パターンにしたがって、
INotifyPropertyChanged インターフェースと ICommand インターフェースが実装されていれば、ViewModel がそのまま利用できる感じになる予定です。

