takataka430’s blog

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

Write Code Every Dayを始めてみた

「Write Code Every Day」とは文字通り毎日コードを書こうという試みです。

【参考】 Write Code Every Day - Speaker Deck

自分もやってみたいと思ったので始めてみました。 なぜ始めたかというと、プライベートでもコードを書く習慣を身に付けたいと思ったからです。

しかし、私は毎日何かをやるのが苦手な人です。そこで自分流のルールを考えてみました。意識したのは、完全に止めてしまわないように、とにかくハードルを下げることです。

その1:意味のないコードでもOKとする

例えばコメントで何か書くとか、不要なコードを削るとか、そういうのでもOKとしました。その方が毎日気軽な気持ちでやる気になれます。

その2:続かなくてもあまり気にしない

仮に忙しかったり寝てしまったりしてその日にコードを書けなかったとしても「しょうがない、次から頑張ろう」とすぐに切り替えるようにしています。変に気にしても落ち込んでしまうので・・・

その3:進捗を見てうっとりする

これが一番重要かもしれません。「おお、できてるじゃん!!」と自分の進捗を見ることで次の日もやろうと思えます。

効果は?

毎日コードを書く、というのは残念ながらまだできていません。しかし、始める前に比べると家でコードを書く頻度は明らかに増えました。

実際の進捗

以下のような感じです。(始めたのは今年の7月です)

f:id:takataka430:20190819224258p:plain

書いてない日も結構多いですが・・・始める前に比べて明らかに頻度が増えていますね。 今後は毎日書いてプッシュするようになりたいです。

というわけで、こんな感じでコツコツ続けていきたいと思います。

Swift愛好会の開発合宿に参加してきました

2019/7/6 - 7/7にSwift愛好会とKotlin愛好会合同の開発合宿が開催されました。

love-swift.connpass.com

love-kotlin.connpass.com

前々からSwiftを使ったモバイルアプリ開発をやりたいと思っていたのですが、家では誘惑が多く、勉強が進まなかったので「自分を追い込もう!!」と思って参加しました。

場所

土善旅館

www.dozenryokan.com

こちらの旅館は開発合宿プランというのがあって、宿泊部屋とは別に開発部屋が用意されます。設備に関しても各自が利用するモニターや、LTを行うためのプロジェクターもあり、とても充実していました。机上にある電源タップは差込口が回転する大変便利なものだったのもよかったです。あと、人をダメにするクッションがあるので寝ながら開発することもできました笑

f:id:takataka430:20190707233310j:plain:w300
電源タップ

合宿の内容

まず到着したら各自が自己紹介、その後各々開発を行います。どんなことをやるかは自分で決めていいので自分のペースで進められます。
合宿の最後に談義というものがあります。これは時間制限が特に設定されていないLTのようなもので、ここで合宿の成果を発表しました。

開発中はお酒とお菓子が出ました。最高の環境でした・・・。

f:id:takataka430:20190707234434j:plain
飲みながら開発!

合宿での個人目標

今回の合宿の私の目標は「SwiftでTodoアプリを作成すること」でした。普段はXamarinを使っているので、Swiftは初心者です。まずはTodoアプリを作ってみようと思いました。
iPhoneアプリを作っている過程で「Kotlinも使いたいなあ」と思ったので、Kotlinを使ったAndroidアプリでHello, World的なこともやってみました。

今回の合宿で最初の一歩を踏み出せたので、今後はオリジナルアプリの開発をしていきたいです!!

まとめ

二日間でSwift、Kotlinの両方を使うことができ、とても勉強になりました。Xamarinだけでなく、今後はネイティブの勉強をやっていこうと思います。
あとはただ勉強するのではなく、「こんなものを作りたい」と思うアプリを作ることを目的にする方が知識が身につきやすいことを合宿で実感したので、まずは何を作りたいかを考えるようにしたいと思います。

とても楽しかったので次回も参加したいです!

【Xamarin.Forms】CheckBoxをListView内で利用して複数選択する(実装編)

前回の記事では複数選択する方法を書きました。

takataka430.hatenablog.com

今回の記事ではチェックを入れた要素を削除する機能を実装してみたいと思います。

*この記事内での「編集モード」はチェックボックスと削除ボタンが表示されている状態を意味します。

コード

画面(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:CheckBox" 
             x:Class="CheckBox.MainPage">
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <!-- チェックした要素を削除するボタン -->
            <Button x:Name="DeleteButton"
                    Text="削除"
                    Clicked="Delete_clicked"
                    TextColor="Red"
                    IsVisible="false"/>
            <!-- 削除ボタンとCheckBoxを非表示にする -->
            <Button x:Name="BackButton"
                    Text="戻る"
                    Clicked="Back_clicked"
                    IsVisible="false"/>
            <!-- 削除ボタンとCheckBoxを表示する -->
            <Button x:Name="EditButton"
                    Text="編集"
                    Clicked="Handle_Clicked"
                    HorizontalOptions="EndAndExpand"/>
        </StackLayout>
        
        <ListView x:Name="list">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            <!-- 2行1列のグリッドを作成 -->
                            <Grid.ColumnDefinitions>
                                <!-- チェックボックスを表示する領域 -->
                                <ColumnDefinition Width="30"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <CheckBox IsChecked="{Binding IsChecked}"
                                      IsVisible="{Binding EditMode}"
                                      Grid.Column="0"/>
                            <Label Text="{Binding Name}"
                                   Grid.Column="1"
                                   VerticalOptions="Center"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

  

コードビハインド(MainPage.Xaml.cs)

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;

namespace CheckBox
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(true)]
    public partial class MainPage : ContentPage
    {
        //編集モードかどうかの状態を保持
        private bool IsEditMode = false;

        //ListView表示用のコレクション
        private ObservableCollection<Person> person = new ObservableCollection<Person>
        {
            new Person{Name = "A"},
            new Person{Name = "B"},
            new Person{Name = "C"},
            new Person{Name = "D"},
            new Person{Name = "E"},
        };

        public MainPage()
        {
            InitializeComponent();

            //ListViewの要素を指定
            list.ItemsSource = person;
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            ChangeMode();
        }

        //チェックしたListViewの要素を削除
        private async void Delete_clicked(object sender, EventArgs e)
        {
            bool isDelete = await DisplayAlert("削除の確認", "選択した項目を削除してよいですか?", "削除する", "キャンセル");
            if (isDelete)
            {
                var itemNumber = person.Count;

                //personコレクションと中身が同じコレクションを新たに作成
                var itemCollection = new ObservableCollection<Person>(person);

                //チェックが入っている要素を削除 
                for (int i = 0; i < itemNumber; i++)
                {
                    var item = itemCollection[i];
                    if (item.IsChecked)
                    {
                        person.Remove(item);
                    }
                }
            }
        }
        
        private void Back_clicked(object sender, EventArgs e)
        {
            ChangeMode();
        }

        //編集モードの切り替えのためのメソッド
        private void ChangeMode()
        {
            IsEditMode = !IsEditMode;
            DeleteButton.IsVisible = IsEditMode;
            BackButton.IsVisible = IsEditMode;
            EditButton.IsVisible = !IsEditMode;

            foreach (var a in person)
            {
                a.EditMode = IsEditMode;

                if (!IsEditMode)
                {
                    a.IsChecked = false;
                }
            }
        }
    }

    //変更通知がいくようにしないとObservableCollectionの要素内のプロパティが変更されても画面に反映されない
    public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                if (name != value)
                {
                    this.name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }

        private bool isChecked;
        public bool IsChecked
        {
            get { return this.isChecked; }
            set
            {
                if (isChecked != value)
                {
                    this.isChecked = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
                }
            }
        }

        private bool editMode;
        public bool EditMode
        {
            get { return this.editMode; }
            set
            {
                if (editMode != value)
                {
                    this.editMode = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(EditMode)));
                }
            }
        }
    }
}

では動きを見てましょう。

f:id:takataka430:20190704232629g:plain:w200

うまく動きました!

実装の失敗例

しかし、削除機能を実装するのに結構苦労しました・・・。何かの参考になるかと思い、失敗した実例をご紹介したいと思います。(Delete_clickedイベントの「チェックが入っている要素を削除 」というコメントがある所の処理です)

失敗1

「繰り返しだからforeachだろう」と思って以下のようなコードにしてみました。

foreach (var item in person)
{
      if (item.IsChecked)
      {
          person.Remove(item);
      }
}

これだとエラーになります。調べてみると、どうやらforeach内でコレクションの追加、削除などはできないようです。こういった処理をしたい場合はfor文を使うといいみたいです。

失敗2

for文を利用して以下のように実装してみました。

for (int i = 0; i < person.Count; i++)
{
       var item = person[i];
       if (item.IsChecked)
       {
           person.Remove(item);
       }
}

これはうまく動くこともありますが、動きが変になります。例えば全ての要素にチェックを入れて削除しようとしても中途半端に残ってしまいます。

これはfor文の中でコレクションの要素の数が変わってしまうためです。person.Countは削除するたびに減少しますし、person[i]は意図した要素が選択されません。これを解決するため、上のコードではpersonと全く同じ別のコレクションを作成しました。
ところでこの方法であってるんでしょうか・・・?あまり自信がないので、修正点あったら教えてください。

  
以上、一例として削除機能を実装してみました。是非皆さんも使ってみてくださいね。それでは!

【Xamarin.Forms】CheckBoxをListView内で利用して複数選択する方法

少し前になりますが、Xamarin.Forms 4.1.0 Pre-Release でチェックボックスが使えるようになりましたね。

devblogs.microsoft.com

実は以前からListViewの要素を複数選択したかったので、これを見た瞬間に「これ使えばできるのでは!?」と思いやり方を調べてみました。iOSの編集モードのような機能を目指しています。それでは早速コードを見てみましょう。

環境

Visual Studio Community 2019 for Mac
Xamarin.Fomrs (4.1.0.496342 pre2)

コード

画面

<?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:CheckBox" 
             x:Class="CheckBox.MainPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="編集"
                     Clicked="Handle_Clicked"/>
    </ContentPage.ToolbarItems>
    <StackLayout>
        <ListView x:Name="list">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            
                            <!-- 2行1列のグリッドを作成 -->
                            <Grid.ColumnDefinitions>
                                
                                <!-- チェックボックスを表示する領域 -->
                                <ColumnDefinition Width="30"/>
                                
                                <ColumnDefinition Width="*"/>
                                
                            </Grid.ColumnDefinitions>
                            
                            <!-- Personクラスのプロパティにバインディング -->
                            <CheckBox IsChecked="{Binding IsChecked}"
                                      IsVisible="{Binding EditMode}"
                                      Grid.Column="0"/>
                            <Label Text="{Binding Name}"
                                   Grid.Column="1"
                                   VerticalOptions="Center"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

コードビハインド

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;

namespace CheckBox
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(true)]
    public partial class MainPage : ContentPage
    {
        //ListView表示用のコレクション
        private ObservableCollection<Person> person = new ObservableCollection<Person>
        {
            new Person{Name = "A"},
            new Person{Name = "B"},
            new Person{Name = "C"},
            new Person{Name = "D"},
            new Person{Name = "E"},
        };

        public MainPage()
        {
            InitializeComponent();

            //ListViewの要素を指定
            list.ItemsSource = person;
        }
        
        //チェックボックスの表示・非表示の切り替え
        void Handle_Clicked(object sender, EventArgs e)
        {
            foreach (var a in person)
            {
                if(a.EditMode == true)
                {
                    a.EditMode = false;
                    a.IsChecked = false;
                }
                else
                {
                    a.EditMode = true;
                }
            }
        }
    }

    //変更通知がいくようにしないとObservableCollectionの要素内のプロパティが変更されても画面に反映されない
    public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                if (name != value)
                {
                    this.name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }

        private bool isChecked;
        public bool IsChecked
        {
            get { return this.isChecked; }
            set
            {
                if (isChecked != value)
                {
                    this.isChecked = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
                }
            }
        }

        private bool editMode;
        public bool EditMode
        {
            get { return this.editMode; }
            set
            {
                if (editMode != value)
                {
                    this.editMode = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(EditMode)));
                }
            }
        }
    }
}

コメントにも書いていますが、PersonクラスにINotifyPropertyChangedインターフェイスを継承させて変更通知が行くようにしないと、EditModeプロパティの値が変更されても画面に反映されません。

それでは画面の動きを見てましょう。

f:id:takataka430:20190629215441g:plain:w200

このコードでは表示・非表示の切り替えのみですが、例えばチェックした要素のみコレクションから削除する機能を実装すれば選択削除ができますね。
ぜひ試してみてください!
  
(2019/7/9 追記) 実装編も書きました↓ takataka430.hatenablog.com

【Xamarin.Forms】ViewModelからDisplayAlertを呼び出す方法

最終更新:2019年5月29日

Xamarin.Formsを使ってMVVMアーキテクチャにする場合、ViewModelからDisplayAlertを呼び出す方法がわからなくて困っていたのですが、実現する方法がありました。

環境

Visual Studio Community 2019 for Mac
Xamarin.Forms (3.6.0.264807)

手順

やり方は意外に簡単でApplication.Current.MainPage.DisplayAlertをViewModelで使うだけです。

引数を3つにするとキャンセルボタンだけのアラート、4つにするとBool値を返すことができます。
docs.microsoft.com

以下、サンプルコードです。 (コードビハインドはInitializeComponent()のみなので省略しています)

View(MainPage.xaml.cs)

<?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:DisplayAlertFromViewModel" 
             x:Class="DisplayAlertFromViewModel.MainPage">
    <ContentPage.BindingContext>
        <local:MainPageViewModel/>
    </ContentPage.BindingContext>
    <StackLayout>
        <Button Text="Alert" 
                Command="{Binding OnButton}"
                HorizontalOptions="Center" 
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

  
ViewModel(MainPageViewModel.cs)

using Xamarin.Forms;

namespace DisplayAlertFromViewModel
{
    public class MainPageViewModel
    {
        public MainPageViewModel()
        {
            OnButton = new Command(async() =>
            {
                var select = await Application.Current.MainPage.DisplayAlert("Alert", "アラートです", "OK","キャンセル");
                if (select)
                    await Application.Current.MainPage.DisplayAlert("Alert", "OKが選択されました", "終了");
                else
                    await Application.Current.MainPage.DisplayAlert("Alert", "キャンセルが選択されました", "終了");
            });
        }

        public Command OnButton { get; }
    }
}

以下のような動きになります。

f:id:takataka430:20190524015457g:plain:w250

これを使えばMVVMなアプリを作りやすくなりそうですね!

App Center Auth で少し苦労した点

最近MBaaS機能が追加されたApp Centerですが、さっそく認証機能(App Center Auth)を試してみました。その時にハマったことのメモです。
  
結論から言いますと、現状App Center Authを使う場合は「マイクロソフトアカウントでログインしたApp Center」を使う必要があるようです。
  

どこでハマった?

基本的には以下のドキュメントの手順に沿っていけばうまくいくと思います。

docs.microsoft.com

ハマったのは以下のページ(「Getting Started with App Center Auth Service」内の「Configure the App Center Auth service」)の6番の場所、つまりApp CenterからAzure AD B2Cに接続するところです。

Getting started with the App Center Auth Service - Visual Studio App Center | Microsoft Docs

私はGithubアカウントを用いてApp Centerにログインしていたのですが、以下のように表示されました。

f:id:takataka430:20190517190454p:plain:w250

文章を読むとマイクロソフトアカウントを用いてログインしたApp CenterでないとAzure AD B2Cを読み込むページが表示されないようです。

ちなみに、中央の「Sign in」ボタンを押すと、マイクロソフトアカウントのログインページに移動します。そのままログイン処理を進めるとマイクロソフトアカウントでログインしたApp Centerにログインした状態になりました。この状態であればAzure AD B2Cを読み込むページが表示されます。

冷静に文章を読めばわかると思うのですが、自分は結構悩んでしまいました。(ドキュメントにはApp Centerのログイン方法って指定されてないですよね・・・?)
  
以上、ご参考になれば幸いです。

App CenterにMBaaSの機能が追加

App Centerに認証(App Center Auth)とデータ連携(App Center Data)の機能がプレビューで追加されましたね。

devblogs.microsoft.com

現状では認証はAzure AD B2C、データ連携はCosmosDBのみの対応のようです。今後はもっと改善していくようなのでフィードバックを送ればもっと機能を追加してくれるのではないかと思います。
  
ところで、MBaaSといえばAzure Mobile Appsがありますね。新しい発表がないなあと思ったら、もう開発はしていないようですね。

github.com

上のリンクの「Future of Azure Mobile Apps」にその旨が書いてあります。
Mobile Apps好きだったので残念ですが、App CenterのMBaaS機能に期待しましょう!