回答編集履歴
1
回答が足らないようなのでコード追加
test
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
1
|
+
> 「gazouByte.db3」にバイナリデータが保存されない。
|
2
|
+
|
2
|
-
少なくとも`
|
3
|
+
**例外を握り潰さないでください**(少なくとも`Debug.WriteLine`等で分かるようにしないと、まともにデバッグもできません)
|
3
|
-
|
4
|
-
---
|
5
4
|
|
6
5
|
ファイルはできるのにレコードが追加されないということは、`gazouconn.Insert`が失敗しているんでしょう。
|
7
6
|
|
@@ -29,3 +28,202 @@
|
|
29
28
|
statusMessage.Text = "got all file list";
|
30
29
|
}
|
31
30
|
```
|
31
|
+
|
32
|
+
---
|
33
|
+
|
34
|
+
> 「Get All GazouList」を押下しても「got all file list」しか表示されず、「Id」「ファイル名」「拡張子」が表示されない。
|
35
|
+
|
36
|
+
`CollectionView`に何も入れていないので当然です。`MainViewModel`にコレクションを用意してバインドしてください。
|
37
|
+
|
38
|
+
バインドについてはこの辺りを確認してください。
|
39
|
+
[データ バインディングの基礎 - .NET MAUI | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/maui/xaml/fundamentals/data-binding-basics)
|
40
|
+
[データ バインディングと MVVM - .NET MAUI | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/maui/xaml/fundamentals/mvvm)
|
41
|
+
|
42
|
+
Toolkitの使い方はこの辺りを確認してください。
|
43
|
+
[MVVM Toolkit の概要 - Community Toolkits for .NET | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/communitytoolkit/mvvm)
|
44
|
+
|
45
|
+
```xml:MainPage.xaml
|
46
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
47
|
+
<ContentPage
|
48
|
+
x:Class="WorkReview.Views.MainPage"
|
49
|
+
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
50
|
+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
51
|
+
xmlns:models="clr-namespace:WorkReview.Models"
|
52
|
+
xmlns:viewModels="clr-namespace:WorkReview.ViewModels"
|
53
|
+
Title="MainPage"
|
54
|
+
x:DataType="viewModels:MainViewModel">
|
55
|
+
<ContentPage.BindingContext>
|
56
|
+
<viewModels:MainViewModel />
|
57
|
+
</ContentPage.BindingContext>
|
58
|
+
<Grid
|
59
|
+
Padding="5"
|
60
|
+
ColumnSpacing="10"
|
61
|
+
RowDefinitions="Auto,Auto,Auto,Auto,Auto,*"
|
62
|
+
RowSpacing="10">
|
63
|
+
<Label Text="{Binding StatusMessage}" TextColor="Red" />
|
64
|
+
<Button Grid.Row="1" Command="{Binding GetAllGazouCommand}" Text="Get All GazouList" />
|
65
|
+
<CollectionView Grid.Row="2" ItemsSource="{Binding GazouBytes}">
|
66
|
+
<CollectionView.ItemTemplate>
|
67
|
+
<DataTemplate x:DataType="models:GazouByte">
|
68
|
+
<Grid ColumnDefinitions="*,2*,*">
|
69
|
+
<Label Text="{Binding Id}" TextColor="{StaticResource Primary}" />
|
70
|
+
<Label Grid.Column="1" Text="{Binding GazouName}" TextColor="{StaticResource Primary}" />
|
71
|
+
<Label Grid.Column="2" Text="{Binding GazouExtension}" TextColor="{StaticResource Primary}" />
|
72
|
+
</Grid>
|
73
|
+
</DataTemplate>
|
74
|
+
</CollectionView.ItemTemplate>
|
75
|
+
</CollectionView>
|
76
|
+
<Button Grid.Row="3" Command="{Binding FileSaveCommand}" Text="ファイルを保存する" />
|
77
|
+
<Button Grid.Row="4" Command="{Binding FileSelectCommand}" Text="ファイルを選択する" />
|
78
|
+
<Image Grid.Row="5" Source="{Binding UserPreview}" />
|
79
|
+
</Grid>
|
80
|
+
</ContentPage>
|
81
|
+
```
|
82
|
+
```cs:MainPage.xaml.cs
|
83
|
+
namespace WorkReview.Views;
|
84
|
+
|
85
|
+
public partial class MainPage : ContentPage
|
86
|
+
{
|
87
|
+
public MainPage() => InitializeComponent();
|
88
|
+
}
|
89
|
+
```
|
90
|
+
|
91
|
+
```cs:MainViewModel.cs
|
92
|
+
using CommunityToolkit.Mvvm.ComponentModel;
|
93
|
+
using CommunityToolkit.Mvvm.Input;
|
94
|
+
using WorkReview.Models;
|
95
|
+
|
96
|
+
namespace WorkReview.ViewModels;
|
97
|
+
|
98
|
+
public partial class MainViewModel : ObservableObject
|
99
|
+
{
|
100
|
+
[ObservableProperty] private string? statusMessage;
|
101
|
+
[ObservableProperty] private List<GazouByte>? gazouBytes;
|
102
|
+
[ObservableProperty] private ImageSource? userPreview;
|
103
|
+
|
104
|
+
private string? gazouName;
|
105
|
+
private byte[]? gazouBinary;
|
106
|
+
private string? gazouExtension;
|
107
|
+
|
108
|
+
public MainViewModel() { }
|
109
|
+
|
110
|
+
[RelayCommand]
|
111
|
+
private void OnGetAllGazou()
|
112
|
+
{
|
113
|
+
GazouBytes = App.GazouByteRepo.GetAllGazouBytes();
|
114
|
+
StatusMessage = "got all file list";
|
115
|
+
}
|
116
|
+
|
117
|
+
[RelayCommand]
|
118
|
+
private void OnFileSave()
|
119
|
+
{
|
120
|
+
if (gazouName == null) return;
|
121
|
+
|
122
|
+
var gazouByte = new GazouByte
|
123
|
+
{
|
124
|
+
GazouName = gazouName,
|
125
|
+
GazouBinary = gazouBinary!,
|
126
|
+
GazouExtension = gazouExtension!,
|
127
|
+
};
|
128
|
+
App.GazouByteRepo.AddNewGazouByte(gazouByte);
|
129
|
+
StatusMessage = "file saved";
|
130
|
+
}
|
131
|
+
|
132
|
+
[RelayCommand]
|
133
|
+
private async Task OnFileSelect()
|
134
|
+
{
|
135
|
+
try
|
136
|
+
{
|
137
|
+
var result = await FilePicker.PickAsync();
|
138
|
+
if (result == null) return;
|
139
|
+
|
140
|
+
var fileName = result.FileName;
|
141
|
+
if (fileName.EndsWith("jpg", StringComparison.OrdinalIgnoreCase) ||
|
142
|
+
fileName.EndsWith("png", StringComparison.OrdinalIgnoreCase))
|
143
|
+
{
|
144
|
+
using (var stream = await result.OpenReadAsync())
|
145
|
+
using (var memoryStream = new MemoryStream())
|
146
|
+
{
|
147
|
+
await stream.CopyToAsync(memoryStream);
|
148
|
+
gazouName = fileName;
|
149
|
+
gazouBinary = memoryStream.ToArray();
|
150
|
+
gazouExtension = result.ContentType;
|
151
|
+
|
152
|
+
var previewStream = new MemoryStream(memoryStream.ToArray());
|
153
|
+
UserPreview = ImageSource.FromStream(() => previewStream);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
else
|
157
|
+
{
|
158
|
+
StatusMessage = "Unsupported file type.";
|
159
|
+
}
|
160
|
+
}
|
161
|
+
catch (Exception ex)
|
162
|
+
{
|
163
|
+
StatusMessage = $"Error selecting file: {ex.Message}";
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
```
|
169
|
+
|
170
|
+
```cs:GazouByteRepositry.cs
|
171
|
+
using SQLite;
|
172
|
+
using System.Diagnostics;
|
173
|
+
|
174
|
+
namespace WorkReview.Models;
|
175
|
+
|
176
|
+
public class GazouByteRepositry
|
177
|
+
{
|
178
|
+
private string gazoudbPath;
|
179
|
+
|
180
|
+
public GazouByteRepositry(string gazoudbPath)
|
181
|
+
{
|
182
|
+
this.gazoudbPath = gazoudbPath;
|
183
|
+
|
184
|
+
using var gazouconn = new SQLiteConnection(gazoudbPath);
|
185
|
+
gazouconn.CreateTable<GazouByte>();
|
186
|
+
}
|
187
|
+
|
188
|
+
public void AddNewGazouByte(GazouByte gazouByte)
|
189
|
+
{
|
190
|
+
ArgumentNullException.ThrowIfNull(gazouByte);
|
191
|
+
|
192
|
+
try
|
193
|
+
{
|
194
|
+
using var gazouconn = new SQLiteConnection(gazoudbPath);
|
195
|
+
var gazouResult = gazouconn.Insert(gazouByte);
|
196
|
+
|
197
|
+
Debug.WriteLine($"Insert result: {gazouResult}");
|
198
|
+
Debug.WriteLine($"{gazouResult} record(s) added (GazouName: {gazouByte.GazouName})");
|
199
|
+
}
|
200
|
+
catch (Exception ex)
|
201
|
+
{
|
202
|
+
Debug.WriteLine($"Failed to add {gazouByte.GazouName}. Error: {ex.Message}");
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
public List<GazouByte> GetAllGazouBytes()
|
207
|
+
{
|
208
|
+
try
|
209
|
+
{
|
210
|
+
using var gazouconn = new SQLiteConnection(gazoudbPath);
|
211
|
+
return gazouconn.Table<GazouByte>().ToList();
|
212
|
+
}
|
213
|
+
catch (Exception ex)
|
214
|
+
{
|
215
|
+
Debug.WriteLine($"Failed to retrieve data .{ex.Message}");
|
216
|
+
}
|
217
|
+
return [];
|
218
|
+
}
|
219
|
+
}
|
220
|
+
```
|
221
|
+
![アプリ動画](https://ddjkaamml8q8x.cloudfront.net/questions/2024-08-14/aefd0c98-9d7c-4339-8af3-3e9f0231d427.gif)
|
222
|
+
|
223
|
+
---
|
224
|
+
|
225
|
+
例外処理はもっと慎重に考えてもらいたい(リカバリーできるものだけ個別にキャッチ等)が、とりあえず形は変えずに最低限メッセージだけは出した。
|
226
|
+
「ViewModelでダイアログ出すのはどうなんだ?」ってのはあるが本題ではないので^^;
|
227
|
+
ほかにも気になる点はあるが、あまり変えても何なんでこのくらいで...
|
228
|
+
|
229
|
+
|