パッケージをインストール
Visual Studio 2022のメニュー→「プロジェクト」→「NuGetパッケージの管理」
ReactiveProperty
System.Reactive
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Sqlite.Core
SQLitePCLRaw.bundle_green
sqlite-net-pcl
検索しインストール
ソースコード
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LastOilChange2.MainPage">
<ScrollView>
<VerticalStackLayout>
<CollectionView
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem.Value}"
SelectionChanged="OnCollectionViewSelectionChanged"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding Memo}"
FontSize="18" />
<Label Grid.Column="1"
Text="{Binding Date}"
FontSize="18" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Label
Text="{Binding SelectedName.Value}"
FontSize="18"/>
<Button
Text="Add"
Margin="8"
Command="{Binding OnAddCliked}" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
ファイル名:MainPage.xaml.cs
namespace LastOilChange2;
public partial class MainPage : ContentPage
{
ViewModel _vm;
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, EventArgs e)
{
_vm = new ViewModel();
this.BindingContext = _vm;
}
private async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = (e.CurrentSelection.FirstOrDefault() as LastUpdate);
if (item != null)
{
var page = new DetailPage(item);
await Navigation.PushModalAsync(page);
}
}
protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
_vm?.UpdateListView();
}
}
ファイル名:DetailPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LastOilChange2.DetailPage"
Title="DetailPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Entry Text="{Binding Memo.Value}"
FontSize="18" />
<Entry Text="{Binding Date.Value}"
FontSize="18" />
<HorizontalStackLayout>
<Button
Text="日付更新"
Margin="8"
Command ="{Binding OnUpdateDate}"
HorizontalOptions="Center" />
<Button
Text="削除"
Margin="8"
Clicked="OnRemoveBtnClicked"
HorizontalOptions="Center" />
<Button
Text="戻る"
Margin="8"
Clicked="OnCloseBtnClicked"
HorizontalOptions="Center" />
</HorizontalStackLayout>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
ファイル名:DetailPage.xaml.cs
namespace LastOilChange2;
public partial class DetailPage : ContentPage
{
DetailViewModel _vm;
public DetailPage(LastUpdate item)
{
InitializeComponent();
_vm = new DetailViewModel(item);
Loaded += (s, e) =>
{
BindingContext = _vm;
};
}
// 戻る
private async void OnCloseBtnClicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
// 削除
private async void OnRemoveBtnClicked(object sender, EventArgs e)
{
var db = new MyDbContext();
db.Remove(_vm.Item);
db.SaveChanges();
await Navigation.PopModalAsync();
}
}
ファイル名:DetailViewModel.cs
using Microsoft.EntityFrameworkCore;
using Reactive.Bindings;
using SQLitePCL;
namespace LastOilChange2;
public class DetailViewModel
{
public ReactiveProperty<string> Memo { get; set; } = new ReactiveProperty<string>("");
public ReactiveProperty<string> Date { get; set; } = new ReactiveProperty<string>("");
public ReactiveCommand OnUpdateDate { get; set; } = new ReactiveCommand();
public LastUpdate Item;
public DetailViewModel(LastUpdate item)
{
var db = new MyDbContext();
this.Item = item;
Memo.Value = item.Memo;
Date.Value = item.Date;
Memo.Subscribe(_ =>
{
item.Memo = Memo.Value;
db.Update(item);
db.SaveChanges();
});
Date.Subscribe(_ =>
{
item.Date = Date.Value;
db.Update(item);
db.SaveChanges();
});
OnUpdateDate.Subscribe(_ =>
{
Date.Value = DateTime.Now.ToString("yyyy/MM/dd");
});
}
}
ファイル名:LastUpdate.cs
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace LastOilChange2;
public class LastUpdate
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public long Id { get; set; }
public string Memo { get; set; } = "";
public string Date { get; set; } = "";
}
ファイル名:MyDbContext.cs
using Microsoft.EntityFrameworkCore;
namespace LastOilChange2;
public class MyDbContext : DbContext
{
public DbSet<LastUpdate> LastUpdate => Set<LastUpdate>();
public string DbPath { get; set; } = "";
public MyDbContext()
{
DbPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/sample.db";
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite($"Data Source={DbPath}");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<LastUpdate>().ToTable("LastUpdate");
}
}
ファイル名:ViewModel.cs
using Microsoft.EntityFrameworkCore;
using Reactive.Bindings;
using SQLitePCL;
namespace LastOilChange2;
public class ViewModel
{
public ReactiveCollection<LastUpdate> Items { get; set; } = new ReactiveCollection<LastUpdate>();
public ReactiveProperty<LastUpdate> SelectedItem { get; } = new ReactiveProperty<LastUpdate>();
public ReactiveProperty<string> SelectedName { get; } = new ReactiveProperty<string>("");
public ReactiveCommand OnAddCliked { get; set; } = new ReactiveCommand();
public void UpdateListView()
{
var db = new MyDbContext();
// ListViewのクリア
Items.Clear();
// レコードの取得
foreach (var r in db.LastUpdate)
{
// ListViewに追加
Items.Add(r);
}
}
public ViewModel()
{
var db = new MyDbContext();
// テーブル作成
db.Database.EnsureCreated();
// レコード件数が0の場合
if (!db.LastUpdate.Any())
{
// 追加
string date = DateTime.Now.ToString("yyyy/MM/dd");
db.Add(new LastUpdate { Memo = "オイル交換", Date = date, });
db.Add(new LastUpdate { Memo = "メモ2", Date = date, });
db.Add(new LastUpdate { Memo = "メモ3", Date = date, });
db.SaveChanges();
}
UpdateListView();
SelectedItem.Subscribe((o) =>
{
// SelectedName.Value = o?.Memo;
});
// 追加
OnAddCliked.Subscribe((o) =>
{
string memo = String.Format("メモ{0}", (Items.Count+1));
string date = DateTime.Now.ToString("yyyy/MM/dd");
var card = new LastUpdate { Memo = memo, Date = date, };
// テーブルに追加
db.Add(card);
db.SaveChanges();
UpdateListView();
});
}
}
実行
「日付更新」ボタンで当日日付に置き換わる。
感想
MAUIを使ってアプリケーションを作ってみて思ったのですが、1つのページ?をルーティングで使いまわす作りが、Webアプリケーションと似たような感じがします。あと、今回はデータをSQLiteに保存するスタンドアローンなアプリケーションを作成してみましたが、スマートフォン1つで完結する要件は余り多くなく、ネットクライアントとしての要件が多いと思います。そうなるとサーバーが欲しいところですが、個人でサーバーを用意するのはハードルが高いので、次の学習ステップとして何をするか検討中です。
コメント