Implemented export to CSV functionality.
This commit is contained in:
1 parent
a478d4ebb0
commit
ddbc745200
4 files changed
+98
-9
No files matched your search
@@ -121,6 +121,55 @@ public class Database {
|
|||||||
|
|
||||||
return coins;
|
return coins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String CollectionToCSV(string collectionName) {
|
||||||
|
var cmd = Connection.CreateCommand();
|
||||||
|
cmd.CommandText = $"SELECT * FROM {collectionName}";
|
||||||
|
|
||||||
|
var headersCommand = Connection.CreateCommand();
|
||||||
|
headersCommand.CommandText = $"PRAGMA table_info({collectionName})";
|
||||||
|
|
||||||
|
var resultString = "";
|
||||||
|
var numHeaders = 0;
|
||||||
|
|
||||||
|
// Get the headers.
|
||||||
|
using (var reader = headersCommand.ExecuteReader()) {
|
||||||
|
while (reader.Read()) {
|
||||||
|
resultString += reader.GetString(1) + ",";
|
||||||
|
numHeaders++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultString += "\n";
|
||||||
|
|
||||||
|
// Is there a more efficient way of doing this? This is running at O(n^2) time.
|
||||||
|
using (var reader = cmd.ExecuteReader()) {
|
||||||
|
while (reader.Read()) {
|
||||||
|
// Read information from the reader, then add to CSV string.
|
||||||
|
for (int i = 0; i < numHeaders; i++) {
|
||||||
|
// Get the type of each column.
|
||||||
|
var type = reader.GetFieldType(i);
|
||||||
|
Console.WriteLine("Type: " + type);
|
||||||
|
if (type == typeof(Int64)) {
|
||||||
|
resultString += reader.GetInt32(i) + ",";
|
||||||
|
}
|
||||||
|
else if (type == typeof(Double)) {
|
||||||
|
resultString += reader.GetDouble(i) + ",";
|
||||||
|
}
|
||||||
|
else if (type == typeof(String)) {
|
||||||
|
resultString += reader.GetString(i) + ",";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resultString += "NULL" + ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultString += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultString;
|
||||||
|
}
|
||||||
|
|
||||||
public Coin? GetCoin(int pcgsNumber, string grade) {
|
public Coin? GetCoin(int pcgsNumber, string grade) {
|
||||||
// Get the coin based off of the pcgs number.
|
// Get the coin based off of the pcgs number.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
@@ -9,8 +10,6 @@ using ReactiveUI;
|
|||||||
|
|
||||||
namespace PcgsInvUi.ViewModels;
|
namespace PcgsInvUi.ViewModels;
|
||||||
|
|
||||||
// TODO Find window.
|
|
||||||
// TODO Export window and export function.
|
|
||||||
// TODO Error handling.
|
// TODO Error handling.
|
||||||
// TODO Manual handling of API key.
|
// TODO Manual handling of API key.
|
||||||
// TODO Use CoinFacts link.
|
// TODO Use CoinFacts link.
|
||||||
@@ -43,6 +42,8 @@ public class MainWindowViewModel : ViewModelBase {
|
|||||||
public Interaction<DeleteWindowViewModel, Boolean> ShowDeleteWindow { get; }
|
public Interaction<DeleteWindowViewModel, Boolean> ShowDeleteWindow { get; }
|
||||||
public ReactiveCommand<Unit, Coin> FindCommand { get; }
|
public ReactiveCommand<Unit, Coin> FindCommand { get; }
|
||||||
public Interaction<FindWindowViewModel, int> ShowFindWindow { get; }
|
public Interaction<FindWindowViewModel, int> ShowFindWindow { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ExportCommand { get; }
|
||||||
|
public Interaction<Unit, Stream> ShowExportWindow { get; }
|
||||||
|
|
||||||
private ViewModelBase _sideContent;
|
private ViewModelBase _sideContent;
|
||||||
private Coin? _selectedCoin;
|
private Coin? _selectedCoin;
|
||||||
@@ -67,12 +68,29 @@ public class MainWindowViewModel : ViewModelBase {
|
|||||||
DeleteCommand = ReactiveCommand.CreateFromTask(async () => {
|
DeleteCommand = ReactiveCommand.CreateFromTask(async () => {
|
||||||
var deleteViewModel = new DeleteWindowViewModel();
|
var deleteViewModel = new DeleteWindowViewModel();
|
||||||
var result = await ShowDeleteWindow.Handle(deleteViewModel);
|
var result = await ShowDeleteWindow.Handle(deleteViewModel);
|
||||||
if (result && SelectedCoin != null) {
|
if (result && SelectedCoin is not null) {
|
||||||
ConnectedDatabase.DeleteCoin(SelectedCoin);
|
ConnectedDatabase.DeleteCoin(SelectedCoin);
|
||||||
CoinCollection.Remove(SelectedCoin); // possible null deref - ignored due to button being disabled.
|
CoinCollection.Remove(SelectedCoin); // possible null deref - ignored due to button being disabled.
|
||||||
}
|
}
|
||||||
}, deleteEnabled);
|
}, deleteEnabled);
|
||||||
|
|
||||||
|
ShowExportWindow = new Interaction<Unit, Stream>();
|
||||||
|
ExportCommand = ReactiveCommand.CreateFromTask(async () => {
|
||||||
|
var stream = await ShowExportWindow.Handle(Unit.Default);
|
||||||
|
var writer = new StreamWriter(stream);
|
||||||
|
try {
|
||||||
|
await writer.WriteAsync(ConnectedDatabase.CollectionToCSV("CollectionTable"));
|
||||||
|
await writer.FlushAsync();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// Something is wrong with the file after it's been created.
|
||||||
|
Console.WriteLine(e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Close();
|
||||||
|
stream.Close();
|
||||||
|
});
|
||||||
|
|
||||||
// Set up the ability to open the find window.
|
// Set up the ability to open the find window.
|
||||||
ShowFindWindow = new Interaction<FindWindowViewModel, int>();
|
ShowFindWindow = new Interaction<FindWindowViewModel, int>();
|
||||||
var findEnabled = this.WhenAnyValue(x => x.CoinCollection.Count,
|
var findEnabled = this.WhenAnyValue(x => x.CoinCollection.Count,
|
||||||
@@ -84,7 +102,7 @@ public class MainWindowViewModel : ViewModelBase {
|
|||||||
// Perhaps a secondary viewmodel?
|
// Perhaps a secondary viewmodel?
|
||||||
return new Coin();
|
return new Coin();
|
||||||
}, findEnabled);
|
}, findEnabled);
|
||||||
|
|
||||||
// Subscribe to SidebarContent.OkCommand, which is an IObservable<(int, string, int)>
|
// Subscribe to SidebarContent.OkCommand, which is an IObservable<(int, string, int)>
|
||||||
// This is the same as the above, but with a different syntax.
|
// This is the same as the above, but with a different syntax.
|
||||||
newViewModel.OkCommand
|
newViewModel.OkCommand
|
||||||
|
|||||||
@@ -65,16 +65,16 @@
|
|||||||
DockPanel.Dock="Left">
|
DockPanel.Dock="Left">
|
||||||
<Button Grid.Column="0" Margin="5" Width="100" HorizontalContentAlignment="Center" Content="Delete"
|
<Button Grid.Column="0" Margin="5" Width="100" HorizontalContentAlignment="Center" Content="Delete"
|
||||||
Command="{Binding DeleteCommand}" />
|
Command="{Binding DeleteCommand}" />
|
||||||
<Button Grid.Column="1" Margin="5" Width="100" HorizontalContentAlignment="Center"
|
<!-- <Button Grid.Column="1" Margin="5" Width="100" HorizontalContentAlignment="Center" -->
|
||||||
Content="Find..."
|
<!-- Content="Find..." -->
|
||||||
Command="{Binding FindCommand}" />
|
<!-- Command="{Binding FindCommand}" /> -->
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5" ColumnDefinitions="Auto, Auto"
|
<Grid HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5" ColumnDefinitions="Auto, Auto"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<Label Grid.Column="0" Margin="5" VerticalAlignment="Center"
|
<Label Grid.Column="0" Margin="5" VerticalAlignment="Center"
|
||||||
Content="{Binding TotalValue, StringFormat='Total Value: ${0:0.00}'}" />
|
Content="{Binding TotalValue, StringFormat='Total Value: ${0:0.00}'}" />
|
||||||
<Button Grid.Column="1" Margin="5" Width="150" HorizontalContentAlignment="Center"
|
<Button Grid.Column="1" Margin="5" Width="150" HorizontalContentAlignment="Center"
|
||||||
Content="Export to CSV..." />
|
Content="Export to CSV..." Command="{Binding ExportCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reactive;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using PcgsInvUi.ViewModels;
|
using PcgsInvUi.ViewModels;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@@ -10,7 +13,8 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel> {
|
|||||||
public MainWindow() {
|
public MainWindow() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(d => d(ViewModel!.ShowDeleteWindow.RegisterHandler(ShowDeleteWindowAsync)));
|
this.WhenActivated(d => d(ViewModel!.ShowDeleteWindow.RegisterHandler(ShowDeleteWindowAsync)));
|
||||||
this.WhenActivated(d => d(ViewModel!.ShowFindWindow.RegisterHandler(ShowFindWindowAsync)));
|
this.WhenActivated(d => d(ViewModel!.ShowExportWindow.RegisterHandler(ShowFilePickerAsync)));
|
||||||
|
// this.WhenActivated(d => d(ViewModel!.ShowFindWindow.RegisterHandler(ShowFindWindowAsync)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ShowDeleteWindowAsync(InteractionContext<DeleteWindowViewModel, Boolean> interaction) {
|
public async Task ShowDeleteWindowAsync(InteractionContext<DeleteWindowViewModel, Boolean> interaction) {
|
||||||
@@ -28,4 +32,22 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel> {
|
|||||||
var result = await window.ShowDialog<int>(this);
|
var result = await window.ShowDialog<int>(this);
|
||||||
interaction.SetOutput(result);
|
interaction.SetOutput(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ShowFilePickerAsync(InteractionContext<Unit, Stream> interationContext) {
|
||||||
|
var topLevel = GetTopLevel(this);
|
||||||
|
var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions {
|
||||||
|
Title = "Save CSV...",
|
||||||
|
DefaultExtension = ".csv",
|
||||||
|
ShowOverwritePrompt = true,
|
||||||
|
SuggestedFileName = "coins.csv",
|
||||||
|
SuggestedStartLocation = await StorageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Documents)
|
||||||
|
});
|
||||||
|
|
||||||
|
Stream stream;
|
||||||
|
|
||||||
|
if (file is not null) {
|
||||||
|
stream = await file.OpenWriteAsync();
|
||||||
|
interationContext.SetOutput(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user