Could not save pictures into db with Maui and SQlite episode2
Episode 1 here
Causing2
Reason for ListView showing Items of picture
ListView must have a List to show at MainViewModel(Binding Context) not only binding ItemSource at Xaml.
Solution
Add the code at MainViewModel then, bind ItemSource.
For your information, [ObserverProperty] can generate automatically to Capital G "GazouByte" at Xaml ItemSource from field gazouByte at MainV MainViewModel
-
namespace WorkReview.ViewModels;
public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string? statusMessage;[ObservableProperty]
private List<GazouByte>? gazouBytes; //here, List for MainPage[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}";
}
}
}
Afterword
As you can see from my past questions, I've been a bit of a pain with my inquiries. I'll try to be more considerate in the future.
I've realized I still have a lot to learn about MVVM and XAML.
But I was really impressed by how easily the people who answered my questions were able to solve problems I'd been stuck on for a week. I hope to be able to do that someday too.
I learned a lot just by asking questions, so thanks for that.
Could not save pictures into db with Maui and SQlite Episode1
Outline
I am creating file manager software with Maui and SQlite, so I reworked this page project
.NET MAUI アプリで SQLite を使用してローカル データを格納する - Training | Microsoft Learn
and save pictures into the db.
However, I cannot save pictures into the db also Listview does not show list.
Then, I ask a question in Teratail and StackOverflow.
Honestly, you can understand the error easily in these page than this blog . I wrote this page for my memorization
Problem Overview
What you are trying to do: I am trying to save image binary data into a SQLite database named gazouByte.db3 when the "Save" button is pressed after selecting an image file using a file picker. Additionally, I want to display the list of saved images, including their "Id," "File Name," and "Extension," in a CollectionView on the MainPage when the "Get All GazouList" button is pressed. What issue you are facing: The image binary data is not being saved to the gazouByte.db3 database. When clicking the "Get All GazouList" button, only "got all file list" is displayed, and the "Id," "File Name," and "Extension" are not shown. Note that the table gazouByte has been confirmed to be created using "DB Browser for SQLite."
-
Expected Behavior
When starting debugging, a table named gazouByte should be created in the app data. After selecting an image using the file picker, the selected image should be previewed under "Select File." When clicking the "Save File" button, the image data should be saved into the gazouByte.db3 database. Clicking the "Get All GazouList" button should display the "Id," "File Name," and "Extension" of the saved images in the CollectionView.
-
What I Have Tried
Verified that exception handling in GazouByteRepositry.AddNewGazouByte method is correctly implemented. Confirmed that the table gazouByte is created using "DB Browser for SQLite." Noticed that a System.NullReferenceException occurs when pressing the "Save File" button again without selecting a new image.
-
Error Messages and Logs
No error messages are displayed, but the image data is not saved.
-
Environment
Windows 11 Home 23H2 Visual Studio Community 2022 Preview 17.11.0 Preview 4.0 Microsoft.Maui.Controls 8.0.80 Microsoft .NET SDK 8.0.107 (x64) SQlitePCLRaw.bundle_green 2.1.9 sqlite-net-pcl 1.9.172 CommunityToolkit.Mvvm 8.2.2
The question pages
Causing
Reason for not saving into db
-
The project had created db dupulicately that's why picture was not saved
-
MainviewModel recreated another db even db had already created at MauiProgram.cs, so pictures were not saved correct 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));//Creating db as instance at App folder.↑ here
return builder.Build();
}
}
}
-
-
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommunityToolkit;
using CommunityToolkit.Mvvm.ComponentModel;
using WorkReview.Models;namespace WorkReview.ViewModels
{
public partial class MainViewModel : ObservableObject
{
private GazouByteRepositry _gazouByteRepositry;public MainViewModel()
{
_gazouByteRepositry = new GazouByteRepositry("gazouByte.db3");//↑ Create duplicately db at here
}[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);
}}
}
Solutions
I deleted the line and insert picture data directly into dbPath throw App.GazouByteRepo."MethodName" .
-
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);//←forexample here
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}";
}
}
}
-
-
Next Episode
*1:In Youtube and .Net . you can watch live streaming video
In Maui 'InitializeComponent()' does not exist in the current context.
Intro (not must read)
I use Visual Studio 2022LTS regularly . It happens to install Preview version, and the IDE says usualy "'InitializeComponent()' does not exist in the current context.". However, it also says
NETSDK1147 if you want to build this project, you need installing these workload wasi-experimental. Run this command for installing dotnet workload restore .
I translated error massages from Japanese to English that’s why sentences is not accurate, But I searched and understand that means workload for Maui and SDK were not installed to my visual studio.
I have tried below solutions then errors purged, so I noted this page.
OutLine
In Maui, I built project for debugging Error List tell me that
-
'InitializeComponent()' does not exist in the current context.
I tried these steps
- Reboot PC
-
Reinstalled VisualStudio and VisualStudio installer
- Installed must have workloads via VisualStudio installer
- Rebuilt the project
- Checked build action at ContentPage is MauiXaml
My environment
-
date 2024/07/21
-
Visual Studio 2022 version 17.10.4 PRE
-
Maui
- CommunityToolkit MVVM
My Solution
- Open command-line tool from tool tab
- Execute this 「dotnet workload restore」
- After in stalled them, also execute 「dotnet workload install maui」
- Reboot your PC after save all
- Check resolve or not in same project
Otheres(not must read)
Have you solve the error?
This can be unique situation in my environment, so if you have any solution or matter please comment . Thank you for reading.
MauiとSQliteでdbにデータが保存できなかったListView編
前回(ここの記事の続きです)
原因
画像がListViewに表示されなかった原因
- ListViewはXaml側でItemSourceを指定するだけではなく、BindingContextのMainViewModelに表示用のListが必要だった
解決法
MainViewModelに該当部分を追加し、ItemSourceをバインドした。
ちなみに、[ObserverProperty]側はgazouBytesでItemSouceはGazouBytesでバインドする。どうやらCommunityToolkit側で自動にフィールド表記を大文字になおしてくれているっぽい。
-
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}";
}
}
}
あとがき(読まなくても大丈夫です)
質問ページを見ていただければ分かる通り、かなり質問法でご迷惑をおかけしている。次回以降質問する機会があれば、その辺に気をつけたい。
まだまだMVVMとXamlに対する理解が足りないと痛感した。
けれども、個人で1週間ほど悩んだが回答をしてくださった方々はあっさり解決してくださったので、私もいつかそうなりたいと思った。
質問しただけだがたくさん学べたので良かった。
MauiとSQliteでdbにデータが保存できなかったdb編
まえがき(必読ではありません)
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公式に追いながら学習できる動画もあります
Mauiで 'InitializeComponent()' does not exist in the current context.
まえがき(必読ではありません)
私はVisualStudio2022のLTSを普段は使用しているが、たまたまVisualStudioの再インストールを2度目に行った段階でPREバージョンをインストールしてしまった。今まで通り「'InitializeComponent()' does not exist in the current context.」が表示されたが、さらに
NETSDK1147 このプロジェクトをビルドするには、次のワークロードをインストールする必要があります: wasi-experimental
これらのワークロードをインストールするには、次のコマンドを実行します: dotnet workload restore
という一文が加えられた。調べて見るとMaui用のワークロードとSDKがうまくインストールされていないようである。
以下に記述した対策を講じたことで、エラーが消えたのでここに備忘録として書き残そうと思う。
概要
Mauiでデスクトップアプリのためにソースコードをしたあとデバックしようとすると、エラー一覧に次のようなメッセージが出た。
-
'InitializeComponent()' does not exist in the current context.
-
'InitializeComponent()'は現在のコンテキストに存在しません。
次のような対策をしてみても再び表示されてしまった。
- PCの再起動
-
VisualStudioおよびVisualStudioインストーラーの再インストール
- Maui等の必須ワークロードを再インストール
- プロジェクト自体の再作成
- ContentPageのビルドアクションをMauiXamlに変更(初期状態からこれになっていた)
以下の環境で行った
-
日付 2024/07/21
-
Visual Studio 2022 バージョン 17.10.4 PRE
-
Maui
- CommunityToolkit MVVM
自己流解決策
- VisualStudioのツールタブからコマンドプロンプトを開く。
- 「dotnet workload restore」を入力し、インストール完了を待機
- インストール完了後「dotnet workload install maui」を入力しインストール完了を待機
- すべて保存後PCの再起動。
- 該当プロジェクトをVisualStudio2022で確認し、エラーが表示されなければ完了。
その他(必読ではありません)
エラーは表示されなくなっただろうか。私はVisualStudioインストーラーでワークロードをきちんとインストールできていなかったのかもしれない。
私の環境特有のエラー理由かもしれないので、他に知見がある方やこの方法で解決できた方がいたら是非コメントしてほしい。読んでくださりありがとう。