回答編集履歴

1

回答が足らないようなのでコード追加

2024/08/14 09:47

投稿

TN8001
TN8001

スコア9819

test CHANGED
@@ -1,7 +1,6 @@
1
- **例外を握り潰さないでください**
1
+ > 「gazouByte.db3」にバイナリデータが保存ない。
2
+
2
- 少なくとも`Console.WriteLine`等で分かるようにしないと、まともにデバッグもできません
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
+