rksoftware

Visual Studio とか C# とかが好きです

Xamarin Forms でバックグラウンド処理内で画面の値を変更する

Xamarin.Forms に限らず多くのプラットフォームでそうなのですが、UI の更新は UI スレッド(メインスレッド)でしか行えません。
例えば、長い時間のかかる処理をスレッドを立ててバックグラウンドで行いつつ、進捗を UI に表示する場合などに少し手間をかけないとエラーになってしまいます。

■ 結論

Xamarin.Forms.Device.BeginInvokeOnMainThread メソッドを使用します。

■ 使用例

次のコードはボタンをクリックすると 10,000 ミリ秒間バックグラウンドのスレッドが実行されます。
その中で、100 ミリ秒ごとに UI の値を変更しています。
※お急ぎの方はコメント「// UI スレッドでラベルの値を更新」の部分だけ見ていただければ OK です。

public partial class MainPage : ContentPage
{
    Label label;
    public MainPage()
    {
        InitializeComponent();

        // UI の構築。ここは本題とは関係ない
        var sl = (StackLayout)(this.Content = new StackLayout());
        var button = new Button() { Text = "button" };
        label = new Label() { Text = "0" };
        sl.Children.Add(button);
        sl.Children.Add(label);
        
        // ボタンクリックで、別スレッドで処理
        button.Clicked += (sender, e) => new System.Threading.Thread(
            new System.Threading.ThreadStart(delegate ()
            {
                for (var i = 0; i < 100; ++i)
                {
                    System.Threading.Thread.Sleep(100);

                    // UI スレッドでラベルの値を更新
                    Xamarin.Forms.Device.BeginInvokeOnMainThread(() =>
                            this.label.Text = DateTime.Now.ToString());
                }
            })
        ).Start();
    }
}