GrapeCity.devlog

グレープシティ株式会社のDeveloper Tools〈開発支援ツール〉の最新情報をお届けします。製品のTIPSや発売情報、イベントのお知らせなどをいち早く発信中です。

Realm Databaseを使用してCRUDアプリを作成(前編)

Realm Databaseを使ってCRUDを実装したシンプルなXamarin.Formsアプリを作ってみます。今回は前編としてCRUDのデータの作成(CREATE)と表示(READ)に該当する部分を作成します。データの表示にはComponentOne Studio for Xamarin(以下、C1 Xamarin)のFlexGridを使用します。

Realm Databaseとは?

Realm DatabaseはSQLiteと同じくローカルデータベースです。このデータベースは近年モバイルアプリをはじめてとして様々なアプリケーションで採用が進んでいます。Realm Databaseを使うメリットについてはオープンソースクロスプラットフォームである、SQLiteより処理が高速である、使い始めるのが簡単など色々と挙げられます。詳細については公式サイトをご覧ください。

realm.io

以下に作成手順を解説します。

Visual Studio 2017でXamarin.Forms (PCL)アプリを作成

まずはいつもどおりXamarin.Forms (PCL)アプリを作成します。現時点で最新のC1 Xamarin(2.3.20172.190)を使用するので各プロジェクトで使用するXamarin.Formsのバージョンを2.3.4.270に設定します。 f:id:ComponentOne_JP:20171114174823p:plain

Realm Databaseのインストール

Nuget パッケージ マネージャーから「Realm」を各プロジェクトにインストールします。 Realmはバージョン1.6をインストールします。 f:id:ComponentOne_JP:20171114180304p:plain

これに合わせてFodyは2.0.6、Newtonsoft.Jsonは9.0.1をインストールします。 f:id:ComponentOne_JP:20171115151149p:plain

f:id:ComponentOne_JP:20171115151209p:plain

また、Realmをインストールすると、各プロジェクトにFodyWeavers.xmlというファイルが作成されますが、UWPには作成されません。他のプロジェクトからコピーしておきます。

f:id:ComponentOne_JP:20171115152035p:plain

C1 Xamarin FlexGridのインストール

Nuget パッケージ マネージャーから「C1 Xamarin FlexGrid」を各プロジェクトにインストールします。 f:id:ComponentOne_JP:20171115152827p:plain

モデルの作成

データモデルを追加します。

public class DataModel : RealmObject
    {
        [PrimaryKey]
        public int Id { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public float Height { get; set; }
        public float Weight { get; set; }
    }
ビューとビューモデルの作成(CREATE)

Realm Databaseにデータを入力するビューとビューモデルを作成します。 ビューのページにはデータを入力する Entry コントロールとRealm DatabaseへのCREATEを実行するボタンを配置します。

<?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="RealmDatabase.View.CreateData">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
      iOS="10, 20, 10, 0" Android="10, 20, 10, 0" WinPhone="10, 20, 10, 0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout>
            <Grid HorizontalOptions="FillAndExpand" VerticalOptions="Center">
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Grid.Row="0" Text="氏名(姓)"></Label>
                <Entry Grid.Column="1" Grid.Row="0" x:Name="lastname" Text="{Binding LastName}"></Entry>
                <Label Grid.Column="0" Grid.Row="1" Text="氏名(名)"></Label>
                <Entry Grid.Column="1" Grid.Row="1" x:Name="firstname" Text="{Binding FirstName}"></Entry>
                <Label Grid.Column="0" Grid.Row="2" Text="身長"></Label>
                <Entry Grid.Column="1" Grid.Row="2" x:Name="height" Text="{Binding Height}"></Entry>
                <Label Grid.Column="0" Grid.Row="3" Text="体重"></Label>
                <Entry Grid.Column="1" Grid.Row="3" x:Name="weight" Text="{Binding Weight}"></Entry>
            </Grid>
            <Button x:Name="writebtn" Text="入力したデータを登録" Command="{Binding WriteDataCommand}"></Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

ビューのコードビハインドではバインディングコンテキストを設定します。

    public partial class CreateData : ContentPage
    {
        public CreateData()
        {
            InitializeComponent();

            var createdatavm = new CreateDataViewModel();
            BindingContext = createdatavm;
        }
    }

ビューモデルではWriteDataメソッドをWriteDataCommandコマンドで呼び出します。WriteDataメソッドでRealm Databaseに入力データを追加しています。

public class CreateDataViewModel : INotifyPropertyChanged
    {
        Realm realm = Realm.GetInstance();

        private string lastname;
        public string LastName
        {
            get { return lastname; }
            set
            {
                lastname = value;
                OnPropertyChanged("LastName");
            }
        }

        private string firstname;
        public string FirstName
        {
            get { return firstname; }
            set
            {
                firstname = value;
                OnPropertyChanged("FirstName");
            }
        }

        private string height;
        public string Height
        {
            get { return height; }
            set
            {
                height = value;
                OnPropertyChanged("Height");
            }
        }

        private string weight;
        public string Weight
        {
            get { return weight; }
            set
            {
                weight = value;
                OnPropertyChanged("Weight");
            }
        }

        public ICommand WriteDataCommand { get; private set; }

        public CreateDataViewModel()
        {
            WriteDataCommand = new Command(WriteData);
        }

        public void WriteData()
        {
            realm.Write(() =>
            {
                realm.Add(new DataModel()
                {
                    Id = realm.All<DataModel>().Count() + 1,
                    LastName = LastName,
                    FirstName = FirstName,
                    Height = float.Parse(Height, System.Globalization.CultureInfo.InvariantCulture),
                    Weight = float.Parse(Weight, System.Globalization.CultureInfo.InvariantCulture)
                });
            });
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
ビューとビューモデルの作成(READ)

Realm Databaseに作成したデータをFlexGridで表示するビューとビューモデルを作成します。 ビューのページにはFlexGrid コントロールを配置します。

<?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="RealmDatabase.View.ListData"
             xmlns:c1="clr-namespace:C1.Xamarin.Forms.Grid;assembly=C1.Xamarin.Forms.Grid">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
      iOS="10, 20, 10, 0" Android="10, 20, 10, 0" WinPhone="10, 20, 10, 0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout>
            <Grid VerticalOptions="FillAndExpand">
                <c1:FlexGrid x:Name="grid" AutoGenerateColumns="False">
                    <c1:FlexGrid.Columns>
                        <c1:GridColumn Header="氏名(姓)" Binding="LastName" />
                        <c1:GridColumn Header="氏名(名)" Binding="FirstName"/>
                        <c1:GridColumn Header="身長" Binding="Height" />
                        <c1:GridColumn Header="体重" Binding="Weight" />
                    </c1:FlexGrid.Columns>
                </c1:FlexGrid>
            </Grid>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

ビューのコードビハインドではバインディングコンテキストを設定します。また、FlexGridのItemSourceにビューモデル内でRealm Databaseにあるデータのコレクションを設定したAllDataを設定します。

public partial class ListData : ContentPage
    {
        public ListData()
        {
            InitializeComponent();

            var listdatavm = new ListDataViewModel();
            BindingContext = listdatavm;
            grid.ItemsSource = listdatavm.AllData;
            grid.IsReadOnly = true;
        }
    }

ビューモデルではAllData にRealm Databaseにあるデータのコレクションを設定しています。

public class ListDataViewModel : INotifyPropertyChanged
    {
        Realm realm = Realm.GetInstance();

        private ObservableCollection<DataModel> alldata;
        public ObservableCollection<DataModel> AllData
        {
            get { return alldata; }
            set
            {
                alldata = value;
            }
        }

        public ListDataViewModel()
        {
            AllData = new ObservableCollection<DataModel>(realm.All<DataModel>());
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
ビューとビューモデルの作成(トップページ)

最後に各ビューのページ(CreateDataとListData)に遷移するボタンを配置したトップページのビューとビューモデルを作成します。

<?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="RealmDatabase.View.MainPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
      iOS="10, 20, 10, 0" Android="10, 20, 10, 0" WinPhone="10, 20, 10, 0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout Padding="10">
            <Button Text="Realm Databaseに登録" Command="{Binding NavToCreateCommand}"/>
            <Button Text="FlexGridで表示" Command="{Binding NavToListCommand}"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

ビューのコードビハインドではバインディングコンテキストを設定します。

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

            var mainvm = new MainViewModel();
            BindingContext = mainvm;
        }
    }

ビューモデルには各ページへのナビゲーションをNavToCreateCommand、NavToListCommand コマンドで追加しています。

class MainViewModel
    {
        public ICommand NavToListCommand { get; private set; }
        public ICommand NavToCreateCommand { get; private set; }

        public MainViewModel()
        {
            NavToListCommand = new Command(async () => await App.Current.MainPage.Navigation.PushAsync(new ListData()));

            NavToCreateCommand = new Command(async () => await App.Current.MainPage.Navigation.PushAsync(new CreateData()));
        }
    }
実行してみる

以上で作成完了です。アプリをビルドして実行してみます。

f:id:ComponentOne_JP:20171116160324p:plainf:id:ComponentOne_JP:20171116160335p:plainf:id:ComponentOne_JP:20171116160349p:plain
Android
f:id:ComponentOne_JP:20171116161533p:plainf:id:ComponentOne_JP:20171116161539p:plainf:id:ComponentOne_JP:20171116161547p:plain
iOS
f:id:ComponentOne_JP:20171116162256p:plainf:id:ComponentOne_JP:20171116162310p:plainf:id:ComponentOne_JP:20171116162330p:plain
UWP

今回はCRUDのCREATE、READを実装しました。今後はUPDATE、DELETEも追加して後編として記事にしたいと思います。


作成したサンプルはこちらで公開しています。C1 Xamarinのライセンスも含まれていますので、NuGetパッケージを復元すれば実行可能です *1

ダウンロード(zipファイル:271KB)


*1:NuGetパッケージを利用するには、GrapeCityのNuGetフィードソース( http://nuget.c1.grapecity.com/nuget/ )を、Visual Studioの環境に追加する必要があります。