takataka430’s blog

.NET系を中心に勉強したことのまとめを書きます

【Xamarin.Forms】ページ間での値の受け渡し方法を考えてみた(コードビハインド編)

最終更新:2019年3月19日

Xamarin.Formsでページ間で値を受け渡しするいい方法がないかと色々考えてみました。今回は次のような簡単な状況を想定します。

最初のページ(MainPage)でEntryに値を入力する

次のページ(SecondPage)で、最初のページのEntryに入力した値をLabelに表示する
  
考えた方法は以下の3通りです。MainPageからSecondPageのどこに値を渡すかで場合分けしています。

1.コンストラクタに値を渡す
2.プロパティに値を渡す
3.メソッドに値を渡す
4.遷移先のページのBindingContextに渡す(2019/3/19 追記)

なお、1~3の画面は共通なので先に掲載します。

MainPage.xaml(値を渡すページ)

<?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:local="clr-namespace:XF_NavigationPage" 
             x:Class="XF_NavigationPage.MainPage">
    <StackLayout VerticalOptions="Center">
        <Entry x:Name="entry"
               HorizontalOptions="FillAndExpand" />
        <Button x:Name="button"
               Text="To Second Page"
               HorizontalOptions="Center"
               Clicked="Handle_Clicked" />
    </StackLayout>
</ContentPage>

     

SecondPage.xaml(値を受け取るページ)

<?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="XF_NavigationPage.SecondPage">
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center">
            <Label Text="前のページから受け取った値"
                   HorizontalOptions="Center"/>
            <Label x:Name="label"
                   HorizontalOptions="Center"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

1.コンストラクタに値を渡す

コードビハインドに以下のように記述します。
  
MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class MainPage : ContentPage
    {

        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            var name = entry.Text;

            Navigation.PushAsync(new SecondPage(name));
        }
    }
}

  
SecondPage.xaml.cs

using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class SecondPage : ContentPage
    {
        public SecondPage(string name)
        {
            InitializeComponent();

            label.Text = name;
        }
    }
}

NavigationPageでSecondPageのインスタンスを作る時にコンストラクタに値を渡しています。
それでは動きを見てみましょう。

f:id:takataka430:20190227224120g:plain:w200

うまくいっていますね!・・がこの方法では困ることがあります。SecondPageのXAMLのプレビューがエラーになるのです。

f:id:takataka430:20190227224330p:plain:w200

これでは画面を作る時に不便なので、この方法はやめたほうが良さそうです。

2.プロパティに値を渡す

それならSecondPageにプロパティを定義して、インスタンスを作る時にプロパティに値を渡せば良いのでは?と考えました。

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class MainPage : ContentPage
    {

        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            var name = entry.Text;

            //SecondPageクラスのNameプロパティに値を渡す
            Navigation.PushAsync(new SecondPage {Name=name});
        }
    }
}

  
SecondPage.xaml.cs

using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class SecondPage : ContentPage
    {
        //コンストラクタ
        public SecondPage()
        {
            InitializeComponent();
        }

        //画面が表示される時に実行
        protected override void OnAppearing()
        {
            NameSet(Name);
        }
        
        //プロパティを追加
        public string Name { get; set; }

        //ラベルのテキストを設定するメソッドを追加
        public void NameSet(string name)
        {
            label.Text = name;
        }
    }
}

最初はOnAppearingなしで、コンストラクタにNameSetメソッドを入れていましたが、それでは値を受け取れませんでした。この対策のためOnAppearingを使っています。
それでは動きを確認してみましょう。

f:id:takataka430:20190227230014g:plain:w200

一応、値は受け渡しできていますが、SecondPageで受け取った値が遅れて表示されるのでちょっと微妙ですね。

3.メソッドに値を渡す

それならメソッドに直接値を渡してしまえばいいのでは?と思ってコードを以下のようにしてみました。

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class MainPage : ContentPage
    {

        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            var name = entry.Text;

            var secondPage = new SecondPage();
            Navigation.PushAsync(secondPage);
            secondPage.NameSet(name);
        }
    }
}

  
SecondPage.xaml.cs

using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class SecondPage : ContentPage
    {
        public SecondPage()
        {
            InitializeComponent();
        }

        public void NameSet(string name)
        {
            label.Text = name;
        }
    }
}

先ほどよりもコードがスッキリしました。動きを確認してみましょう。
  
f:id:takataka430:20190227230923g:plain:w200

いい感じです。今回行った方法の中で一番良さそうです。   

4.遷移先のページのBindingContextに渡す(2019/3/19 追記)

以下のようにSecondPageのBindingContextにMainPageのentryを渡し、SecondPageのLabelにバインドする方法でもできました。

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XF_NavigationPage
{
    public partial class MainPage : ContentPage
    {

        public MainPage()
        {
            InitializeComponent();
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new SecondPage()
            {
                BindingContext = entry
            });
        }
    }
}

  
SeconaPage.xaml

<?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="XF_NavigationPage.SecondPage">
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center">
            <Label Text="前のページから受け取った値"
                   HorizontalOptions="Center"/>
            <Label Text="{Binding Text}"
                   HorizontalOptions="Center"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

動きは3と同じだったので省略します。

まとめ

今回のような簡単な場合はコードビハインドに書くだけでいいのかもしれませんが、やはりしっかりやるならMVVMを使ってやった方がいいのではないかと思いました。それについては調べてみようと思います。

【Xamarin.Forms】ProgressBarを使い、繰り返し処理の進捗を表示してみた

モバイルアプリで何か処理をするために数十秒くらいの時間がかかる場合、ユーザーからするといつ終わるのか目安みたいなものが欲しいですよね?このような場合にどうすればいいのか調べていたところ、Xamarin.Formsには「ProgressBar」というものがあることを知りました。

ProgressBarとは

進捗を表すコントローラのことです。このクラスはProgressというプロパティを持っており、ここに値(最大値は1)を入れることによって進捗バーの色の領域が変わります。例えば、Progressプロパティが0.4の場合は以下の画像のようになります。

f:id:takataka430:20190221203806p:plain:w200

画像の通り、左から40%が色付きの領域になっていることがわかります。
詳しくは以下のドキュメントをご覧ください。

docs.microsoft.com

繰り返し処理の進捗をProgressBarで表示してみた

それでは本題です。今回はコレクションから要素を一つずつ取り出し、何らかの処理を繰り返す場合を考えてみました。コードは以下の通りです。

画面

<?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:local="clr-namespace:XF_ProgressBar" 
             x:Class="XF_ProgressBar.MainPage">
    <StackLayout VerticalOptions="Center">
        <Button x:Name="button"
                Text="Button"
                Clicked="Handle_Clicked"/>
        <ProgressBar x:Name="progress"/>
        <Label x:Name="label"
               HorizontalOptions="Center"/>
    </StackLayout>
</ContentPage>

  
コードビハインド

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XF_ProgressBar
{
    public partial class MainPage : ContentPage
    {
        //1が1000個あるコレクション
        IEnumerable<int> numbers = Enumerable.Repeat(1, 1000);

        public MainPage()
        {
            InitializeComponent();
        }

        async void Handle_Clicked(object sender, EventArgs e)
        {
            label.Text = "";
            int sum = 0;
            var amount = numbers.Count();    //コレクションの要素数
            var operated = 0;                //処理済みの回数を初期化
            foreach(var number in numbers) 
            {
                sum = sum + number;
                operated += 1;
                progress.Progress = (double)operated / amount;  //ここで進捗率を計算
                await Task.Delay(1);                            //一瞬で終わってしまうので見やすいように1ミリ秒待つようにしています
                label.Text = sum.ToString();
            }
        }
    }
}

1が1000個入っているコレクションから値を一つずつ取り出し加算するという処理を行い、ProgressBarで進捗を表しています。また、加算の結果は随時ラベルで表示するようにしています。
実行すると以下のようになります。

f:id:takataka430:20190221203709g:plain:w200

いい感じですね!
今回行った加算処理を他の処理に置き換えれば色々な進捗の表示に使えるのではないかと思います。

【Xamarin.Forms】Behaviorを使って入力値検証(その2:ボタンと連動させる)

前回の記事ではEntryの文字の色を変えるところまでやりました。今回はそれに加えてボタンと連携し、条件を満たす文字列の場合にのみボタンが有効になるようにしてみます。
  
目標は「Entryに入力した文字列がhttps://で始まれば文字は黒、ボタンは有効化される。そうでない場合は文字は赤、ボタンは有効化されない」です。
  
これを実現するため、Xamarin.FormsのMessagingCenterという機能を使いました。

docs.microsoft.com

MessagingCenterとは、簡単に言いますとメッセージの送受信ができる機能です。Sendでメッセージを送信し、Subscribeでメッセージを受信して処理を行います。

では実際にどのようにコードを書いたのか見てみましょう。(前回の記事からの変更部分のみコメントをしています)   
  
UrlValidationBehavior.cs

using System;
using Xamarin.Forms;

namespace XF_EntryCheck
{
    public class UrlValidationBehavior : Behavior<Entry>
    {
        //設定した条件を満たすかどうか判定
        public bool IsValid { get; set; }

        protected override void OnAttachedTo(Entry bindable)
        {
            bindable.TextChanged += OnEntryTextChanged;
            base.OnAttachedTo(bindable);
        }

        protected override void OnDetachingFrom(Entry bindable)
        {
            bindable.TextChanged -= OnEntryTextChanged;
            base.OnDetachingFrom(bindable);
        }

        void OnEntryTextChanged(object sender, TextChangedEventArgs args)
        {
            var m = args.NewTextValue.StartsWith("https://", StringComparison.Ordinal);

            ((Entry)sender).TextColor = m ? Color.Default : Color.Red;

            //判定結果を代入
            IsValid = m;

            //メッセージの送信
            MessagingCenter.Send(this, "IsValid");
        }
    }
}

  

MainPage.xaml

<?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:local="clr-namespace:XF_EntryCheck" 
             x:Class="XF_EntryCheck.MainPage">
    <StackLayout VerticalOptions="Center">
        <Entry x:Name="entry"
               Placeholder="Entry">
            <Entry.Behaviors>
                <local:UrlValidationBehavior x:Name="urlValidationBehavior"/>
            </Entry.Behaviors>
        </Entry>
        
        <!-- ボタンを追加 -->
        <Button x:Name="button"    
                Text="Button"
                HorizontalOptions="Center" />
        
    </StackLayout>
</ContentPage>

  
MainPage.xaml.cs

using Xamarin.Forms;

namespace XF_EntryCheck
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            //メッセージの受信
            MessagingCenter.Subscribe<UrlValidationBehavior>(this, "IsValid", (sender) =>
            {
                EntryChanged();
            });
        }

        //ボタンの有効・無効を判定
        void EntryChanged()
        {
            button.IsEnabled = urlValidationBehavior.IsValid;
        }
    }
}

UrlValidationBehavior.csOnEntryTextChangedイベントが実行された時にメッセージを送信し、MainPageクラスがメッセージを受信後、EntryChanged()を実行するという動きになっています。

それでは早速動かしてみましょう。
目標は「Entryに入力した文字列がhttps://で始まれば文字は黒、ボタンは有効化される。そうでない場合は文字は赤、ボタンは有効化されない」です。

f:id:takataka430:20190216203054g:plain:w250

実現したかった動作は出来ていますね!

参考にしたページ

Xamarin.Forms の MessagingCenter - Xamarin | Microsoft Docs
Xamarin.Formsでビヘイビアーを使用するには? - Build Insider

【Xamarin.Forms】Behaviorを使って入力値検証(その1:文字列の色を変える)

Xamarin.FormsでEntryに文字列を入力する時に入力した値によって色を変えたり下にあるボタンを有効化・無効化するという動きを実現したいと思い、方法を調べました。今回の記事は「条件によってEntryの文字列の色を変える」というのをやってみたいと思います。

やり方

これを実現するにはXamarin.FormsのBehaviorという機能を使えばできるようです。

docs.microsoft.com

早速実装してみましょう。

まずはBehaviorクラスを継承したUrlValidationBehaviorクラスを作ります。

using System;
using Xamarin.Forms;

namespace XF_EntryCheck
{
    public class UrlValidationBehavior : Behavior<Entry>
    {
       //ビヘイビアを追加
        protected override void OnAttachedTo(Entry bindable)
        {
            bindable.TextChanged += OnEntryTextChanged;
            base.OnAttachedTo(bindable);
        }

        //ビヘイビアを削除
        protected override void OnDetachingFrom(Entry bindable)
        {
            bindable.TextChanged -= OnEntryTextChanged;
            base.OnDetachingFrom(bindable);
        }

        //Entryに入力された値が変わった時の動作
        void OnEntryTextChanged(object sender, TextChangedEventArgs args)
        {
            //「https://」で始まる文字列かどうかを判定
            var m = args.NewTextValue.StartsWith("https://", StringComparison.Ordinal);

            //mがtrueなら文字はデフォルトの色、falseなら赤色に変更
            ((Entry)sender).TextColor = m ? Color.Default : Color.Red;
        }
    }
}

コメントにあるように、Entryに入力した文字列が「https://」で始まっていれば文字の色が黒に、そうでない場合は赤に変更する動きになります。

次に画面を作ります。

<?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:local="clr-namespace:XF_EntryCheck" 
             x:Class="XF_EntryCheck.MainPage">
    <StackLayout VerticalOptions="Center">
        <Entry x:Name="entry">

            <!-- このEntryに「UrlValidationBehavior」をアタッチする -->
            <Entry.Behaviors>
                <local:UrlValidationBehavior />
            </Entry.Behaviors>

        </Entry>
    </StackLayout>
</ContentPage>

これでEntryに入力した値は先ほど作ったUrlValidationBehaviorクラスで定義した通り、「https://」で始まっているかどうかによって文字の色が変わります。

動作確認

f:id:takataka430:20190214205151p:plain:w250    f:id:takataka430:20190214205148p:plain:w250

ちゃんと色が変わっていますね!

次にButtonと連携して、条件を満たしている場合のみButtonが有効化されるようにしたいと思います。・・・が、続きは次回にしたいと思います。 (以下、次回のリンクです)

takataka430.hatenablog.com

参考ページ

Xamarin.Forms のビヘイビアー - Xamarin | Microsoft Docs
Xamarin.Formsでビヘイビアーを使用するには? - Build Insider

Azure SQL データベースを無料プランで作る方法を試してみた

個人でAzureのサブスクリプションを作って勉強しようと思った時、無料プランが無いと二の足を踏みますよね?
Azure SQLデータベースは普通に作ると一番安いプランでも月に600円ちょっとかかってしまいます。無料で使う方法は無いのでしょうか?

調べて見たところ、無料で作成する方法があることがわかりました。Azure AppService経由でデータベースを作れば無料プランを選択することができるのです。

参考にしたのは以下のブログです(ありがとうございます!)

www.nuits.jp

というわけで早速自分でもやってみたいと思います。

SQLデータベースを無料プランで作る

前提

AppService(WebApp)とAzure SQL Serverがすでに作られていること
(ここではAppServiceのWebAppで行いますが、モバイルアプリでもできることを確認済みです)

手順

AppService左側メニューの「モバイル」欄の「データ接続」をクリックします。右側に出てきたメニュー上部の「追加」 を選択します。
f:id:takataka430:20190210163453p:plain


「必要な設定の構成」→「新しいデータベースの作成」→「価格レベル」の順番で選択していきます。
f:id:takataka430:20190210163449p:plain


表示されたプラン一覧を見ると「Free」というプランがあることがわかります。これを選択してデータベースの作成・接続を行えば無料でSQLデータベースを使うことができます。
(自動でBasicに移行すると書いてあるので、このプランは期間限定なのかもしれません)
f:id:takataka430:20190210163445p:plain


無料プランのデータベース2つ目を作ろうとしたが・・・

やってみましたがエラーになってしまいました。SQL Server・AppServiceを変更して試してみましたがやはりエラーになってしまいます。もしかしたら無料プランのデータベースはサブスクリプションに1つしか作れないのかもしれません。


以上がAzure SQLデータベースを無料プランで作る方法です。このデータベースは32MBしかないので本番には使えないと思いますが、ちょっとした検証や学習目的に使うのにはとてもいいと思います。

「Azure Functions と キューで構築するNoOpsスケーラブルバッチ処理基盤」に参加してきました

2月6日(水)に行われた以下のイベントに参加してきました。

azure.connpass.com

以前からAzure Functionsを使えるようになりたいと思っていたので、今回のハンズオンを通して実際にどのように使うのかを学ぶために参加しました。

内容

Queue Storageに大量のデータを投入し、Azure Functionを用いてデータを処理した後、処理結果をAzure Cosmos DBに格納するという内容をハンズオンで体験することができました。

学んだこと

どのサービスも初めて使ったので特徴などを調べてまとめました。

  • Azure Functions とは:
    ビジネスロジックを関数として実行する。「HTTP要求」や「Queue Storageに追加されているメッセージの受信」といったイベントによって駆動する。

  • Queue Storageとは:
    メッセージングの仕組みを提供する。処理前のデータを待たせて、その後の処理を順番に実行するためのもの。

  • Azure Cosmos DBとは:
    Azureのデータベースサービスの1つ。NoSQLといわれるもの。世界中に分散してデータを保存できる、動作がリレーショナルデータベースよりも高速、といった特徴がある。

感想

ドキュメントを読んだり一人で動かしてみるよりも、こういったハンズオンに参加した方が理解は早いと感じました。ただ内容がやや高度だったのでもう少し予習をして参加すればよかったと思いました。

ラベルをスクロール表示する方法【Xamarin.Forms】

Xamarin.Formsでラベルに長めの文章を載せたい場合に、画面からはみ出てしまう部分をスクロールで表示したい、ということがあったのでその方法を調べたメモです。(画面はXAMLで書くことを前提とします)

結論から言いますと、このような場合はScrollViewを使えば簡単に実装することができます。
使い方は以下のようにLabelScrollViewで囲むだけです。

<ScrollView>
            <Label Text="ここに長い文章を書く"  />
</ScrollView>

Orientationプロパティを指定することによって、スクロールの方向を「水平方向」「垂直方向」「水平および垂直方向」の3種類から指定することができます。(上のコードのように何も指定しないと垂直方向のスクロールになるようです)

<!--水平方向の場合 -->
<ScrollView Orientation="Horizontal">
            <Label Text="ここに長い文章を書く"  />
</ScrollView>
<!--垂直方向の場合 -->
<ScrollView Orientation="Vertical">
            <Label Text="ここに長い文章を書く"  />
</ScrollView>
<!--水平および垂直方向の場合 -->
<ScrollView Orientation="Both">
            <Label Text="ここに長い文章を書く"  />
</ScrollView>

意外と簡単に出来るんですね!

ところで、上記のOrientationのように、何も指定しない場合の既定値ってどこかに載ってないんですかね?公式ドキュメントを見ても見つからなかったので気になりました。

参考URL

Xamarin.Forms ScrollView - Xamarin | Microsoft Docs