動的に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#のコード内に埋め込んで記述ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); |
文字列から動的に変換するので、ファイルリソースをプロジェクトに埋め込ませて読み込むこともできます。
1 2 3 4 5 6 7 8 9 10 | [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 です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 を参照できるようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 を作ったときと同じように、各種のプロパティが設定できます。
1 2 3 | 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 がそのまま利用できる感じになる予定です。