まえがき(必読ではありません)
MauiとSQLiteをつかってファイル管理のソフトを作ろうと思い、次の
.NET MAUI アプリで SQLite を使用してローカル データを格納する - Training | Microsoft Learn
で作成したソフトを改造してdbに画像を保存できるようにしようと考えた。
しかし、学習ページと動画を見ながらやっても、dbに画像が保存できない。
また、ListViewに画像一覧を表示することもできなかった。
そこで、TeratailとStackOverflow(英)に質問してみた。
正直、このページよりも実際のやり取りを先述ページから見たほうがわかると思う。
しかし頭の中で整理するためここに一応記す。
概要
やりたいこと
- ビルド後appファイルにdb.3ファイルを作成
- file pickerで選択した画像をプレビューに表示
-
保存押下でdbに画像が保存される
- 「Get All GazouList」を押下することで「gazouByte.db3」に保存されたファイルの「Id」「ファイル名」「拡張子」がCollectionViewに表示される。
試したこと
- GazouByteRepositry.AddNewGazouByte メソッドで例外処理が正しく行われていることを確認
- 画像を選択し、保存ボタンを押した後、再度画像を選択せずに保存ボタンを押すとSystem.NullReferenceExceptionが発生することを確認
- Table[("gazouByte")]が作成されていることを「DB Browser for SQlite」で確認
以下の環境で行った
-
日付 2024/08
-
Visual Studio 2022 バージョン 17.10.4 PRE
-
Maui
- CommunityToolkit MVVM
- SQlite
実際の質問
原因
画像が保存できなかった原因
- データーベースが二重に作成されており、画像の保存ができなかった。
- MauiProgram.csの次の部分で既に画像dbが作成されているにもかかわらず、 MainViewModelで上書き作成されていたため正しいPathに画像が保存できなかった。
-
namespace WorkReview
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
string dbPath = FileAccessHelper.GetLocalFilePath("gazouByte.db3");
builder.Services.AddSingleton< GazouByteRepositry> (s => ActivatorUtilities.CreateInstance< GazouByteRepositry> (s, dbPath));//Appの部分にインスタンスとしてdbを作成↑の部分
return builder.Build();
}
}
}
-
namespace WorkReview.ViewModels
{
public partial class MainViewModel : ObservableObject
{
private GazouByteRepositry _gazouByteRepositry;public MainViewModel()
{
_gazouByteRepositry = new GazouByteRepositry("gazouByte.db3");↑の部分で新しいインスタンスで上書きしている
}[ObservableProperty]
public string gazouName;[ObservableProperty]
public string gazouPath;
[ObservableProperty]
public byte gazouBinary;
[ObservableProperty]
public string gazouExtension;
public void SaveGazouToDataBase()//MainPageから渡された画像データをRepositryへ送る。
{
var gazouByte = new GazouByte
{
GazouName = gazouName,
GazouBinary = gazouBinary,
GazouExtension = gazouExtension};
_gazouByteRepositry.AddNewGazouByte(GazouName, GazouBinary, GazouExtension);
}}
}
解決法
MainViewModelの該当部を削除し、App.GazouByteRepo.メソッド名で直接dbPathへ処理を行うようにした。
-
namespace WorkReview.ViewModels;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string? statusMessage;[ObservableProperty]
private List<GazouByte>? gazouBytes; //MainPageのListView用のリスト。ListViewにはC#側にリストを作る必要がある。[ObservableProperty]
private ImageSource? userPreview; //MainPageのプレビュー用
private string? gazouName; //ファイル名private byte? gazouBinary; //画像のバイナリデータ
private string? gazouExtension; //拡張子情報
public MainViewModel()
{ }[RelayCommand]
private void OnGetAllGazou() //画像リストの取得ボタン
{
GazouBytes = App.GazouByteRepo.GetAllGazouBytes();
StatusMessage = "got all file list"; StatusMessage = "got all file list";}
[RelayCommand]
private void OnFileSave()
{
if (gazouName == null) return;var gazouByte = new GazouByte
{
GazouName = gazouName!,
GazouBinary = gazouBinary!, //!はNull出ないことを宣言GazouExtension = gazouExtension!,
};App.GazouByteRepo.AddNewGazouByte(gazouByte);
StatusMessage = "file saved";
}
[RelayCommand]
private async Task OnFileSelect() //非同期でTaskとして結果を返す{
try
{
var result = await FilePicker.PickAsync();
if (result == null) return;
var fileName = result.FileName;if (fileName.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) ||
fileName.EndsWith("png", StringComparison.OrdinalIgnoreCase))
{
using (var stream = await result.OpenReadAsync())
using (var memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
gazouName = fileName;
gazouBinary = memoryStream.ToArray();
gazouExtension = result.ContentType;
var previewStream = new MemoryStream(memoryStream.ToArray());UserPreview = ImageSource.FromStream(() => previewStream);
}
}
else
{
StatusMessage = "Unsupported file type.";
}
}
catch (Exception ex)
{
StatusMessage = $"Error selecting file: {ex.Message}";
}
}
}
次回
「MauiとSQliteでdbにデータが保存できなかったListView編」へ続く
*1:Youtubeと.Net公式に追いながら学習できる動画もあります