using System.Collections.ObjectModel; using System.Text.Json; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DotNetSolutionTools.App.Models; using DotNetSolutionTools.App.Services; using DotNetSolutionTools.Core; using DotNetSolutionTools.Core.Common; namespace DotNetSolutionTools.App.ViewModels; public partial class MainWindowViewModel : ObservableObject { private readonly FileService _fileService = new(); [ObservableProperty] private string _solutionFolderPath = string.Empty; [ObservableProperty] private string _solutionFilePath = string.Empty; [ObservableProperty] private string _csprojFilePath = string.Empty; [ObservableProperty] private ObservableCollection _operationResults = new() { }; [ObservableProperty] private string _resultsLabel = "Ready"; [RelayCommand] private async Task ExecuteParityChecker(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { var results = SolutionProjectParity.CompareSolutionAndCSharpProjects( SolutionFolderPath, SolutionFilePath ); foreach (var result in results) OperationResults.Add(result); ResultsLabel = $"{results.Count} Projects in folder missing from solution"; }, token ); } catch (Exception e) { ResultsLabel = "Failed to compare solution and csharp projects"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task FormatCsProjFile(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { FormatCsproj.FormatCsprojFile(CsprojFilePath); }, token ); ResultsLabel = "Successfully formatted csproj file"; } catch (Exception e) { ResultsLabel = "Failed to format csproj file"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task FormatAllCsprojFilesInSolutionFile(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { var solutionFile = SlnHelper.ParseSolutionFileFromPath(SolutionFilePath); var csprojList = CsprojHelper.RetrieveAllCSharpProjectFullPathsFromSolution(solutionFile); foreach (var csproj in csprojList) { FormatCsproj.FormatCsprojFile(csproj); } }, token ); ResultsLabel = "Successfully formatted all csproj files in solution file"; } catch (Exception e) { ResultsLabel = "Failed to format all csproj files in solution file"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task FormatAllCsprojFilesInSolutionFolder(CancellationToken token) { OperationResults.Clear(); try { ResultsLabel = "Running..."; await Task.Run( () => { var csprojList = CsprojHelper.RetrieveAllCSharpProjectFullPathsFromFolder(SolutionFolderPath); foreach (var csproj in csprojList) { FormatCsproj.FormatCsprojFile(csproj); } }, token ); ResultsLabel = "Successfully formatted all csproj files in folder"; } catch (Exception e) { ResultsLabel = "Failed to format all csproj files in solution folder"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task CheckForMissingImplicitUsingsInSolutionFile(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { var results = ImplicitUsings.FindCSharpProjectsMissingImplicitUsings(SolutionFilePath); results.ForEach(s => OperationResults.Add(s)); ResultsLabel = $"{results.Count} Projects missing ImplicitUsings"; }, token ); } catch (Exception e) { ResultsLabel = "Failed to check for missing implicit usings in solution file"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task CheckForMissingTreatWarningsAsErrorsInSolutionFile(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { var results = WarningsAsErrors.FindCSharpProjectsMissingTreatWarningsAsErrors(SolutionFilePath); results.ForEach(s => OperationResults.Add(s)); ResultsLabel = $"{results.Count} Projects missing TreatWarningsAsErrors"; }, token ); } catch (Exception e) { ResultsLabel = "Error"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task DeleteBinAndObjFoldersInFolder(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( () => { CleanFolder.DeleteBinObjAndNodeModulesFoldersInFolder(SolutionFolderPath); }, token ); ResultsLabel = "Successfully deleted bin and obj folders"; } catch (Exception e) { ResultsLabel = "Failed to delete bin and obj folders"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task UpdateAllProjectsToNet80(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( async () => { await DotNetUpgrade.UpdateProjectsInSolutionToNet80(SolutionFilePath); }, token ); ResultsLabel = "Successfully updated all projects in solution to .NET 8"; } catch (Exception e) { ResultsLabel = "Failed to update all projects in solution to .NET 8"; OperationResults?.Add(e.Message); OperationResults?.Add(e.ToString()); } } [RelayCommand] private async Task UpdateProjectToNet80(CancellationToken token) { OperationResults.Clear(); ResultsLabel = string.Empty; try { ResultsLabel = "Running..."; await Task.Run( async () => { await DotNetUpgrade.UpdateProjectAtPathToNet80(CsprojFilePath); }, token ); ResultsLabel = "Successfully updated project to .NET 8"; } catch (Exception e) { ResultsLabel = "Failed to update project to .NET 8"; OperationResults?.Add(e.Message); } } [RelayCommand] private async Task LoadSolutionFile(CancellationToken token) { try { var file = await _fileService.DoOpenFilePickerSlnAsync(); if (file is null) return; SolutionFilePath = file.Path.AbsolutePath; await SaveLoadedState(); } catch (Exception e) { ResultsLabel = "Error"; OperationResults?.Add(e.Message); } } [RelayCommand] private async Task ClearSolutionFile(CancellationToken token) { SolutionFilePath = string.Empty; await SaveLoadedState(); } [RelayCommand] private async Task LoadSolutionFolder(CancellationToken token) { try { var folder = await _fileService.DoOpenFolderPickerAsync(); if (folder is null) return; SolutionFolderPath = folder.Path.AbsolutePath; await SaveLoadedState(); } catch (Exception e) { ResultsLabel = "Error"; OperationResults?.Add(e.Message); } } [RelayCommand] private async Task ClearSolutionFolder(CancellationToken token) { SolutionFolderPath = string.Empty; await SaveLoadedState(); } [RelayCommand] private async Task LoadCsprojFile(CancellationToken token) { try { var folder = await _fileService.DoOpenFilePickerCsprojAsync(); if (folder is null) return; CsprojFilePath = folder.Path.AbsolutePath; await SaveLoadedState(); } catch (Exception e) { ResultsLabel = "Error"; OperationResults?.Add(e.Message); } } [RelayCommand] private async Task ClearCsprojFile(CancellationToken token) { CsprojFilePath = string.Empty; await SaveLoadedState(); } private async Task SaveLoadedState() { var dto = new LocalStateDto { SolutionFolderPath = SolutionFolderPath, SolutionFilePath = SolutionFilePath, CsprojFilePath = CsprojFilePath }; var json = JsonSerializer.Serialize(dto); await File.WriteAllTextAsync("./localState.json", json); } private async Task LoadSavedState() { try { var json = await File.ReadAllTextAsync("./localState.json"); if (string.IsNullOrEmpty(json)) return; var dto = JsonSerializer.Deserialize(json); if (dto is null) return; SolutionFolderPath = dto.SolutionFolderPath; SolutionFilePath = dto.SolutionFilePath; CsprojFilePath = dto.CsprojFilePath; } catch { // ignored } } public MainWindowViewModel() { LoadSavedState().ConfigureAwait(false); } }