NuGetでXamarin.Forms.XamlProvilderを公開しました

動的に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 がそのまま利用できる感じになる予定です。

カテゴリー: C#, Xamarin パーマリンク