Introduce Avalonia as a new cross-platform UI option, including new XAML and code-behind files for the application and main window. Update Program.cs to support a --avalonia launch argument and add corresponding launch profile. Integrate Avalonia NuGet packages and ensure DataModel supports UI-thread invocation for all frontends. All business logic and state are shared via DI, enabling consistent behavior across WinForms, WPF, and Avalonia.
151 lines
5.8 KiB
C#
151 lines
5.8 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Interactivity;
|
|
using Avalonia.Media.Imaging;
|
|
using Avalonia.Platform.Storage;
|
|
using Avalonia.Styling;
|
|
using Avalonia.Threading;
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace ImageCatalog_2;
|
|
|
|
public partial class AvaloniaMainWindow : Window
|
|
{
|
|
private readonly DataModel _model;
|
|
private bool _isDarkTheme = false;
|
|
|
|
public AvaloniaMainWindow(DataModel model)
|
|
{
|
|
InitializeComponent();
|
|
_model = model;
|
|
DataContext = _model;
|
|
|
|
// Provide Avalonia dispatcher so DataModel can marshal UI updates
|
|
_model.UiInvoker = action => Dispatcher.UIThread.Invoke(action);
|
|
|
|
// Wire dialog events
|
|
_model.SelectSourceFolderRequested += async (_, _) =>
|
|
{
|
|
var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella sorgente" });
|
|
if (folders.Count > 0) _model.SourcePath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar;
|
|
};
|
|
|
|
_model.SelectDestinationFolderRequested += async (_, _) =>
|
|
{
|
|
var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella destinazione" });
|
|
if (folders.Count > 0) _model.DestinationPath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar;
|
|
};
|
|
|
|
_model.SelectLogoFileRequested += async (_, _) =>
|
|
{
|
|
var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
|
{
|
|
Title = "Seleziona logo",
|
|
FileTypeFilter = new[] { new FilePickerFileType("Immagini") { Patterns = new[] { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif" } } }
|
|
});
|
|
if (files.Count > 0)
|
|
{
|
|
_model.LogoFile = files[0].Path.LocalPath;
|
|
UpdateLogoPreview(_model.LogoFile);
|
|
}
|
|
};
|
|
|
|
_model.SelectModelsFolderRequested += async (_, _) =>
|
|
{
|
|
var folders = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = "Seleziona cartella modelli" });
|
|
if (folders.Count > 0) _model.ModelsFolderPath = folders[0].Path.LocalPath + Path.DirectorySeparatorChar;
|
|
};
|
|
|
|
_model.SelectCsvOutputRequested += async (_, _) =>
|
|
{
|
|
var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
|
{
|
|
Title = "Salva CSV",
|
|
DefaultExtension = "csv",
|
|
FileTypeChoices = new[] { new FilePickerFileType("CSV") { Patterns = new[] { "*.csv" } } }
|
|
});
|
|
if (file != null) _model.CsvOutputPath = file.Path.LocalPath;
|
|
};
|
|
|
|
_model.SaveSettingsRequested += async (_, _) =>
|
|
{
|
|
var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
|
{
|
|
Title = "Salva impostazioni",
|
|
DefaultExtension = "xml",
|
|
FileTypeChoices = new[] { new FilePickerFileType("Setup") { Patterns = new[] { "*.xml" } } }
|
|
});
|
|
if (file != null) await _model.SaveSettingsToFileAsync(file.Path.LocalPath);
|
|
};
|
|
|
|
_model.LoadSettingsRequested += async (_, _) =>
|
|
{
|
|
var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
|
{
|
|
Title = "Carica impostazioni",
|
|
FileTypeFilter = new[] { new FilePickerFileType("Setup") { Patterns = new[] { "*.xml" } } }
|
|
});
|
|
if (files.Count > 0) await _model.LoadSettingsFromFileAsync(files[0].Path.LocalPath);
|
|
};
|
|
|
|
_model.SelectColorRequested += (_, _) =>
|
|
{
|
|
// Color is set by typing hex directly in the TextBox
|
|
};
|
|
|
|
_model.SelectTransparentColorRequested += (_, _) =>
|
|
{
|
|
// Color is set by typing hex directly in the TextBox
|
|
};
|
|
|
|
_model.PropertyChanged += (_, e) =>
|
|
{
|
|
if (e.PropertyName == nameof(_model.LogoFile))
|
|
UpdateLogoPreview(_model.LogoFile);
|
|
};
|
|
}
|
|
|
|
private void ToggleTheme_Click(object? sender, RoutedEventArgs e)
|
|
{
|
|
_isDarkTheme = !_isDarkTheme;
|
|
if (Avalonia.Application.Current != null)
|
|
Avalonia.Application.Current.RequestedThemeVariant = _isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light;
|
|
}
|
|
|
|
private void OpenSourceFolder_Click(object? sender, RoutedEventArgs e) => OpenInExplorer(_model.SourcePath);
|
|
private void OpenDestinationFolder_Click(object? sender, RoutedEventArgs e) => OpenInExplorer(_model.DestinationPath);
|
|
private void OpenModelsFolder_Click(object? sender, RoutedEventArgs e) => OpenInExplorer(_model.ModelsFolderPath);
|
|
private void OpenCsvOutputFolder_Click(object? sender, RoutedEventArgs e)
|
|
{
|
|
var dir = Path.GetDirectoryName(_model.CsvOutputPath);
|
|
OpenInExplorer(string.IsNullOrWhiteSpace(dir) ? _model.CsvOutputPath : dir);
|
|
}
|
|
|
|
private static void OpenInExplorer(string? path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
path = path.Trim().Trim('"');
|
|
try
|
|
{
|
|
if (File.Exists(path))
|
|
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{path}\"");
|
|
else if (Directory.Exists(path))
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = path, UseShellExecute = true });
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
private void UpdateLogoPreview(string? path)
|
|
{
|
|
var preview = this.FindControl<Avalonia.Controls.Image>("LogoPreview");
|
|
if (preview == null) return;
|
|
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
|
{
|
|
preview.Source = null;
|
|
return;
|
|
}
|
|
try { preview.Source = new Avalonia.Media.Imaging.Bitmap(path); }
|
|
catch { preview.Source = null; }
|
|
}
|
|
}
|