iteration 1
This commit is contained in:
@@ -23,7 +23,15 @@ namespace CodeContextGenerator.Models
|
||||
_isSelected = value;
|
||||
OnPropertyChanged();
|
||||
UpdateParentSelection();
|
||||
UpdateChildrenSelection(value);
|
||||
|
||||
// Если это директория и установлено конкретное значение (не null), применяем ко всем детям
|
||||
if (IsDirectory && value.HasValue)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.IsSelected = value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,18 +51,27 @@ namespace CodeContextGenerator.Models
|
||||
var allSelected = children.All(c => c.IsSelected == true);
|
||||
var noneSelected = children.All(c => c.IsSelected == false);
|
||||
|
||||
Parent.IsSelected = allSelected ? true : (noneSelected ? false : null);
|
||||
// Если есть дети с null - устанавливаем null
|
||||
bool hasIndeterminate = children.Any(c => c.IsSelected == null);
|
||||
|
||||
if (hasIndeterminate)
|
||||
{
|
||||
Parent.IsSelected = null;
|
||||
}
|
||||
else if (allSelected)
|
||||
{
|
||||
Parent.IsSelected = true;
|
||||
}
|
||||
else if (noneSelected)
|
||||
{
|
||||
Parent.IsSelected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent.IsSelected = null;
|
||||
}
|
||||
|
||||
Parent.UpdateParentSelection();
|
||||
}
|
||||
|
||||
private void UpdateChildrenSelection(bool? value)
|
||||
{
|
||||
if (!IsDirectory || !value.HasValue) return;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
child.IsSelected = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,37 @@
|
||||
using System.IO;
|
||||
using CodeContextGenerator.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace CodeContextGenerator.Services;
|
||||
|
||||
public static class ProjectScannerService
|
||||
namespace CodeContextGenerator.Services
|
||||
{
|
||||
private static readonly string[] ExcludedDirectories = { "bin", "obj", ".git", "packages", ".vs", "Properties", "node_modules", ".vscode" };
|
||||
private static readonly string[] IncludedExtensions = { ".cs", ".xaml" };
|
||||
|
||||
public static async Task<FileItem> ScanProjectDirectoryAsync(string rootPath, IProgress<int> progress = null, CancellationToken cancellationToken = default)
|
||||
public static class ProjectScannerService
|
||||
{
|
||||
var rootItem = new FileItem
|
||||
{
|
||||
Name = Path.GetFileName(rootPath),
|
||||
FullName = rootPath,
|
||||
IsDirectory = true,
|
||||
IsSelected = false
|
||||
private static readonly string[] ExcludedDirectories = {
|
||||
"bin", "obj", ".git", "packages", ".vs", "Properties",
|
||||
"node_modules", ".vscode", ".idea", ".vs", "Debug", "Release"
|
||||
};
|
||||
|
||||
await BuildDirectoryTreeAsync(rootPath, rootItem, progress, cancellationToken);
|
||||
return rootItem;
|
||||
}
|
||||
private static readonly string[] IncludedExtensions = { ".cs", ".xaml" };
|
||||
|
||||
private static async Task BuildDirectoryTreeAsync(string path, FileItem parentItem, IProgress<int> progress = null, CancellationToken cancellationToken = default)
|
||||
public static async Task BuildDirectoryTreeAsync(string path, FileItem parentItem, IProgress<int> progress = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
return;
|
||||
|
||||
var directories = Directory.GetDirectories(path)
|
||||
.Where(d => !ExcludedDirectories.Any(ex => d.EndsWith(ex, StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(d => !ExcludedDirectories.Any(ex => d.EndsWith(ex, System.StringComparison.OrdinalIgnoreCase) ||
|
||||
Path.GetFileName(d).Equals(ex, System.StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
|
||||
var files = Directory.GetFiles(path)
|
||||
.Where(f => IncludedExtensions.Any(ext => f.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(f => IncludedExtensions.Any(ext => f.EndsWith(ext, System.StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
|
||||
int totalItems = directories.Count + files.Count;
|
||||
@@ -85,32 +83,14 @@ public static class ProjectScannerService
|
||||
progress?.Report((int)((processedItems * 100.0) / totalItems));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (IOException)
|
||||
{
|
||||
// Логируем ошибку, но продолжаем работу
|
||||
Console.WriteLine($"Error scanning directory {path}: {ex.Message}");
|
||||
// Игнорируем ошибки доступа к директориям
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
// Игнорируем ошибки доступа
|
||||
}
|
||||
|
||||
public static List<string> GetSelectedFiles(FileItem rootItem)
|
||||
{
|
||||
var selectedFiles = new List<string>();
|
||||
CollectSelectedFiles(rootItem, selectedFiles);
|
||||
return selectedFiles;
|
||||
}
|
||||
|
||||
private static void CollectSelectedFiles(FileItem item, List<string> selectedFiles)
|
||||
{
|
||||
if (item.IsDirectory)
|
||||
{
|
||||
foreach (var child in item.Children)
|
||||
{
|
||||
CollectSelectedFiles(child, selectedFiles);
|
||||
}
|
||||
}
|
||||
else if (item.IsSelected==true)
|
||||
{
|
||||
selectedFiles.Add(item.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,29 @@
|
||||
using CodeContextGenerator.Models;
|
||||
using CodeContextGenerator.Services;
|
||||
using Microsoft.Win32;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Win32;
|
||||
using CodeContextGenerator.Models;
|
||||
using CodeContextGenerator.Services;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CodeContextGenerator.ViewModels
|
||||
{
|
||||
public class MainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private FileItem _rootDirectory;
|
||||
private string _selectedFolderPath;
|
||||
private string _selectedProjectFilePath;
|
||||
private bool _isProcessing;
|
||||
private int _progressValue;
|
||||
private string _progressText;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private string _lastProjectPath;
|
||||
private bool _isProjectLoaded;
|
||||
|
||||
public FileItem RootDirectory
|
||||
{
|
||||
@@ -30,12 +35,12 @@ namespace CodeContextGenerator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public string SelectedFolderPath
|
||||
public string SelectedProjectFilePath
|
||||
{
|
||||
get => _selectedFolderPath;
|
||||
get => _selectedProjectFilePath;
|
||||
set
|
||||
{
|
||||
_selectedFolderPath = value;
|
||||
_selectedProjectFilePath = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -72,17 +77,27 @@ namespace CodeContextGenerator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanSelectFolder => !IsProcessing;
|
||||
public bool CanGenerate => !IsProcessing && RootDirectory != null && HasSelectedFiles(RootDirectory);
|
||||
public bool IsProjectLoaded
|
||||
{
|
||||
get => _isProjectLoaded;
|
||||
set
|
||||
{
|
||||
_isProjectLoaded = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand SelectFolderCommand { get; }
|
||||
public bool CanSelectFolder => !IsProcessing;
|
||||
public bool CanGenerate => !IsProcessing && IsProjectLoaded && HasSelectedFiles(RootDirectory);
|
||||
|
||||
public ICommand SelectProjectFileCommand { get; }
|
||||
public ICommand GenerateCommand { get; }
|
||||
public ICommand CancelCommand { get; }
|
||||
public ICommand ExitCommand { get; }
|
||||
|
||||
public MainViewModel()
|
||||
{
|
||||
SelectFolderCommand = new RelayCommand(SelectFolderAsync);
|
||||
SelectProjectFileCommand = new RelayCommand(SelectProjectFileAsync);
|
||||
GenerateCommand = new RelayCommand(GenerateFileAsync, _ => CanGenerate);
|
||||
CancelCommand = new RelayCommand(CancelProcessing, _ => IsProcessing);
|
||||
ExitCommand = new RelayCommand(_ => Application.Current.Shutdown());
|
||||
@@ -92,6 +107,8 @@ namespace CodeContextGenerator.ViewModels
|
||||
|
||||
private bool HasSelectedFiles(FileItem item)
|
||||
{
|
||||
if (item == null) return false;
|
||||
|
||||
if (item.IsSelected == true && !item.IsDirectory)
|
||||
return true;
|
||||
|
||||
@@ -104,17 +121,17 @@ namespace CodeContextGenerator.ViewModels
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void SelectFolderAsync(object parameter)
|
||||
private async void SelectProjectFileAsync(object parameter)
|
||||
{
|
||||
if (!CanSelectFolder) return;
|
||||
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
Title = "Выберите файл проекта или папку",
|
||||
CheckFileExists = false,
|
||||
Title = "Выберите файл решения или проекта",
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
FileName = "dummy",
|
||||
Filter = "Проекты C# (*.csproj)|*.csproj|Все файлы (*.*)|*.*"
|
||||
Filter = "Файлы решений Visual Studio (*.sln)|*.sln|Файлы проектов C# (*.csproj)|*.csproj|Все поддерживаемые файлы (*.sln;*.csproj)|*.sln;*.csproj|Все файлы (*.*)|*.*",
|
||||
Multiselect = false
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(_lastProjectPath) && Directory.Exists(_lastProjectPath))
|
||||
@@ -126,52 +143,65 @@ namespace CodeContextGenerator.ViewModels
|
||||
|
||||
if (result == true)
|
||||
{
|
||||
string selectedPath = dialog.FileName;
|
||||
string projectDirectory = Path.GetDirectoryName(selectedPath);
|
||||
string selectedFilePath = dialog.FileName;
|
||||
string projectDirectory = Path.GetDirectoryName(selectedFilePath);
|
||||
|
||||
if (!string.IsNullOrEmpty(projectDirectory))
|
||||
{
|
||||
_lastProjectPath = projectDirectory;
|
||||
SaveSettings();
|
||||
|
||||
await LoadProjectDirectoryAsync(projectDirectory);
|
||||
SelectedProjectFilePath = selectedFilePath;
|
||||
IsProjectLoaded = false;
|
||||
|
||||
await LoadProjectAsync(selectedFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadProjectDirectoryAsync(string projectDirectory)
|
||||
private async Task LoadProjectAsync(string projectFilePath)
|
||||
{
|
||||
IsProcessing = true;
|
||||
ProgressText = "Сканирование проекта...";
|
||||
ProgressText = "Загрузка проекта...";
|
||||
ProgressValue = 0;
|
||||
|
||||
try
|
||||
{
|
||||
SelectedFolderPath = projectDirectory;
|
||||
string projectDirectory = Path.GetDirectoryName(projectFilePath);
|
||||
SelectedProjectFilePath = projectFilePath;
|
||||
|
||||
var progress = new Progress<int>(value =>
|
||||
{
|
||||
ProgressValue = value;
|
||||
ProgressText = $"Сканирование: {value}%";
|
||||
ProgressText = $"Загрузка: {value}%";
|
||||
});
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
RootDirectory = await ProjectScannerService.ScanProjectDirectoryAsync(
|
||||
projectDirectory,
|
||||
progress,
|
||||
_cancellationTokenSource.Token
|
||||
);
|
||||
|
||||
ProgressText = "Сканирование завершено";
|
||||
// Определяем тип файла
|
||||
if (projectFilePath.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await LoadSolutionAsync(projectFilePath, progress, _cancellationTokenSource.Token);
|
||||
}
|
||||
else if (projectFilePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await LoadProjectDirectoryAsync(projectDirectory, progress, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
IsProjectLoaded = true;
|
||||
ProgressText = "Проект загружен успешно";
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
ProgressText = "Сканирование отменено";
|
||||
ProgressText = "Загрузка отменена";
|
||||
RootDirectory = null;
|
||||
IsProjectLoaded = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Ошибка при сканировании проекта: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show($"Ошибка при загрузке проекта: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
RootDirectory = null;
|
||||
IsProjectLoaded = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -179,11 +209,137 @@ namespace CodeContextGenerator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadSolutionAsync(string solutionPath, IProgress<int> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
string solutionDirectory = Path.GetDirectoryName(solutionPath);
|
||||
var solutionProjects = ParseSolutionProjects(solutionPath);
|
||||
|
||||
var solutionItem = new FileItem
|
||||
{
|
||||
Name = Path.GetFileName(solutionPath),
|
||||
FullName = solutionPath,
|
||||
IsDirectory = true,
|
||||
IsSelected = false
|
||||
};
|
||||
|
||||
int totalProjects = solutionProjects.Count;
|
||||
int processedProjects = 0;
|
||||
|
||||
foreach (var projectPath in solutionProjects)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (File.Exists(projectPath))
|
||||
{
|
||||
string projectDir = Path.GetDirectoryName(projectPath);
|
||||
string projectName = Path.GetFileName(projectDir);
|
||||
|
||||
var projectItem = new FileItem
|
||||
{
|
||||
Name = projectName,
|
||||
FullName = projectDir,
|
||||
IsDirectory = true,
|
||||
Parent = solutionItem,
|
||||
IsSelected = false
|
||||
};
|
||||
|
||||
await ProjectScannerService.BuildDirectoryTreeAsync(projectDir, projectItem, progress, cancellationToken);
|
||||
|
||||
if (projectItem.Children.Any())
|
||||
{
|
||||
solutionItem.Children.Add(projectItem);
|
||||
}
|
||||
}
|
||||
|
||||
processedProjects++;
|
||||
progress?.Report((int)((processedProjects * 100.0) / totalProjects));
|
||||
}
|
||||
|
||||
RootDirectory = solutionItem;
|
||||
|
||||
// После загрузки решения - не выбираем ничего по умолчанию
|
||||
ClearAllSelections(solutionItem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Ошибка при обработке решения: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> ParseSolutionProjects(string solutionPath)
|
||||
{
|
||||
var projects = new List<string>();
|
||||
try
|
||||
{
|
||||
string solutionDirectory = Path.GetDirectoryName(solutionPath);
|
||||
|
||||
foreach (string line in File.ReadAllLines(solutionPath))
|
||||
{
|
||||
if (line.Trim().StartsWith("Project(", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var parts = line.Split(new[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 3)
|
||||
{
|
||||
string relativePath = parts[2].Trim();
|
||||
string absolutePath = Path.GetFullPath(Path.Combine(solutionDirectory, relativePath));
|
||||
|
||||
if (absolutePath.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) && File.Exists(absolutePath))
|
||||
{
|
||||
projects.Add(absolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Ошибка парсинга файла решения: {ex.Message}", ex);
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
|
||||
private async Task LoadProjectDirectoryAsync(string projectDirectory, IProgress<int> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var projectName = Path.GetFileName(projectDirectory);
|
||||
var rootItem = new FileItem
|
||||
{
|
||||
Name = projectName,
|
||||
FullName = projectDirectory,
|
||||
IsDirectory = true,
|
||||
IsSelected = false
|
||||
};
|
||||
|
||||
await ProjectScannerService.BuildDirectoryTreeAsync(projectDirectory, rootItem, progress, cancellationToken);
|
||||
|
||||
RootDirectory = rootItem;
|
||||
|
||||
// После загрузки проекта - не выбираем ничего по умолчанию
|
||||
ClearAllSelections(rootItem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Ошибка при загрузке проекта: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearAllSelections(FileItem item)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
foreach (var child in item.Children)
|
||||
{
|
||||
ClearAllSelections(child);
|
||||
}
|
||||
}
|
||||
|
||||
private async void GenerateFileAsync(object parameter)
|
||||
{
|
||||
if (!CanGenerate || RootDirectory == null) return;
|
||||
|
||||
var selectedFiles = ProjectScannerService.GetSelectedFiles(RootDirectory);
|
||||
var selectedFiles = GetSelectedFiles(RootDirectory);
|
||||
|
||||
if (selectedFiles.Count == 0)
|
||||
{
|
||||
@@ -195,7 +351,7 @@ namespace CodeContextGenerator.ViewModels
|
||||
{
|
||||
Title = "Сохранить контекстный файл",
|
||||
Filter = "Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*",
|
||||
FileName = $"{Path.GetFileName(SelectedFolderPath)}_context.txt",
|
||||
FileName = $"{Path.GetFileNameWithoutExtension(SelectedProjectFilePath)}_context.txt",
|
||||
DefaultExt = ".txt"
|
||||
};
|
||||
|
||||
@@ -244,6 +400,28 @@ namespace CodeContextGenerator.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetSelectedFiles(FileItem rootItem)
|
||||
{
|
||||
var selectedFiles = new List<string>();
|
||||
CollectSelectedFiles(rootItem, selectedFiles);
|
||||
return selectedFiles;
|
||||
}
|
||||
|
||||
private void CollectSelectedFiles(FileItem item, List<string> selectedFiles)
|
||||
{
|
||||
if (item.IsDirectory)
|
||||
{
|
||||
foreach (var child in item.Children)
|
||||
{
|
||||
CollectSelectedFiles(child, selectedFiles);
|
||||
}
|
||||
}
|
||||
else if (item.IsSelected == true)
|
||||
{
|
||||
selectedFiles.Add(item.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GenerateContextFileAsync(List<string> selectedFiles, string outputPath, IProgress<int> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var outputContent = new StringBuilder();
|
||||
@@ -256,7 +434,8 @@ namespace CodeContextGenerator.ViewModels
|
||||
|
||||
try
|
||||
{
|
||||
string relativePath = Path.GetRelativePath(SelectedFolderPath, filePath);
|
||||
string projectDir = Path.GetDirectoryName(SelectedProjectFilePath);
|
||||
string relativePath = Path.GetRelativePath(projectDir, filePath);
|
||||
string fileContent = await File.ReadAllTextAsync(filePath, Encoding.UTF8);
|
||||
|
||||
// Обработка комментариев
|
||||
@@ -273,13 +452,12 @@ namespace CodeContextGenerator.ViewModels
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Если файл заблокирован или недоступен - останавливаем процесс
|
||||
throw new IOException($"Файл '{Path.GetFileName(filePath)}' заблокирован или недоступен: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Сохраняем результат с кодировкой UTF-8 с BOM для максимальной совместимости
|
||||
var encoding = new UTF8Encoding(true); // true для BOM
|
||||
// Сохраняем результат с кодировкой UTF-8 с BOM
|
||||
var encoding = new UTF8Encoding(true);
|
||||
await File.WriteAllTextAsync(outputPath, outputContent.ToString(), encoding);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +1,68 @@
|
||||
<Window
|
||||
x:Class="CodeContextGenerator.Views.MainWindow"
|
||||
<Window x:Class="CodeContextGenerator.Views.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CodeContextGenerator.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:CodeContextGenerator.Models"
|
||||
Title="Code Context Generator"
|
||||
Width="800"
|
||||
Height="600"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
xmlns:local="clr-namespace:CodeContextGenerator.Views"
|
||||
mc:Ignorable="d"
|
||||
Title="Code Context Generator" Height="600" Width="800"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
|
||||
<Window.Resources>
|
||||
<Style TargetType="TreeViewItem">
|
||||
<Setter Property="IsExpanded" Value="True" />
|
||||
<Setter Property="IsExpanded" Value="True"/>
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Padding" Value="10,5"/>
|
||||
<Setter Property="Margin" Value="5,0"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,5"
|
||||
FontWeight="Bold"
|
||||
Text="Выберите папку проекта:" />
|
||||
<TextBlock Grid.Row="0" Text="Выберите файл решения (.sln) или проекта (.csproj):" FontWeight="Bold" Margin="0,0,0,5"/>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0,0,0,10"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="0,0,10,0"
|
||||
Padding="10,5"
|
||||
Command="{Binding SelectFolderCommand}"
|
||||
Content="Выбрать папку..."
|
||||
IsEnabled="{Binding CanSelectFolder}" />
|
||||
<TextBlock
|
||||
MaxWidth="600"
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
|
||||
<Button Content="Выбрать файл..."
|
||||
Command="{Binding SelectProjectFileCommand}"
|
||||
IsEnabled="{Binding CanSelectFolder}"
|
||||
Width="120"/>
|
||||
<TextBlock Text="{Binding SelectedProjectFilePath}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding SelectedFolderPath}"
|
||||
TextWrapping="Wrap" />
|
||||
TextWrapping="Wrap"
|
||||
MaxWidth="600"
|
||||
Margin="10,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
Padding="5"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<ScrollViewer>
|
||||
<TreeView ItemsSource="{Binding RootDirectory.Children}" Visibility="{Binding RootDirectory, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
<Border Grid.Row="2" BorderBrush="Gray" BorderThickness="1" CornerRadius="4" Padding="5"
|
||||
Visibility="{Binding IsProjectLoaded, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
|
||||
PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
|
||||
<TreeView x:Name="ProjectTree" ItemsSource="{Binding RootDirectory.Children}"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling">
|
||||
<TreeView.ItemTemplate>
|
||||
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox
|
||||
Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsThreeState="True" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
|
||||
<StackPanel Orientation="Horizontal" MinHeight="24">
|
||||
<CheckBox IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsThreeState="True"
|
||||
VerticalAlignment="Center" Margin="2,0,5,0"
|
||||
Click="CheckBox_Click"/>
|
||||
<TextBlock Text="{Binding Name}" VerticalAlignment="Center"
|
||||
ToolTip="{Binding FullName}"/>
|
||||
</StackPanel>
|
||||
</HierarchicalDataTemplate>
|
||||
</TreeView.ItemTemplate>
|
||||
@@ -74,46 +70,27 @@
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<ProgressBar
|
||||
Grid.Row="3"
|
||||
Height="20"
|
||||
Margin="0,10,0,10"
|
||||
<TextBlock Grid.Row="2" Text="Проект еще не загружен. Выберите файл решения или проекта."
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="Gray" FontSize="14"
|
||||
Visibility="{Binding IsProjectLoaded, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Collapsed}"/>
|
||||
|
||||
<ProgressBar Grid.Row="3" Value="{Binding ProgressValue}" Height="20" Margin="0,10,0,10"
|
||||
Visibility="{Binding IsProcessing, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Text="{Binding ProgressText}" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center" FontWeight="Bold"
|
||||
Visibility="{Binding IsProcessing, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
|
||||
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||
<Button Content="Отмена" Command="{Binding CancelCommand}"
|
||||
Visibility="{Binding IsProcessing, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Value="{Binding ProgressValue}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="Bold"
|
||||
Text="{Binding ProgressText}"
|
||||
Visibility="{Binding IsProcessing, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="0,0,10,0"
|
||||
Padding="15,5"
|
||||
Background="#FFDC3545"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="Отмена"
|
||||
Foreground="White"
|
||||
Visibility="{Binding IsProcessing, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<Button
|
||||
Margin="0,0,10,0"
|
||||
Padding="15,5"
|
||||
Command="{Binding ExitCommand}"
|
||||
Content="Закрыть" />
|
||||
<Button
|
||||
Padding="15,5"
|
||||
Background="#FF28A745"
|
||||
Command="{Binding GenerateCommand}"
|
||||
Content="Сформировать"
|
||||
Foreground="White"
|
||||
IsEnabled="{Binding CanGenerate}" />
|
||||
Background="#FFDC3545" Foreground="White"/>
|
||||
<Button Content="Закрыть" Command="{Binding ExitCommand}"/>
|
||||
<Button Content="Сформировать" Command="{Binding GenerateCommand}"
|
||||
IsEnabled="{Binding CanGenerate}"
|
||||
Background="#FF28A745" Foreground="White"
|
||||
Visibility="{Binding IsProjectLoaded, Converter={StaticResource BooleanToVisibilityConverter}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,5 +1,8 @@
|
||||
using System.Windows;
|
||||
using CodeContextGenerator.Models;
|
||||
using CodeContextGenerator.ViewModels;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace CodeContextGenerator.Views
|
||||
{
|
||||
@@ -8,7 +11,30 @@ namespace CodeContextGenerator.Views
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new MainViewModel();
|
||||
}
|
||||
|
||||
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
if (sender is ScrollViewer scrollViewer)
|
||||
{
|
||||
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta / 3);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckBox_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is CheckBox checkBox && checkBox.DataContext is FileItem fileItem)
|
||||
{
|
||||
// Принудительно обновляем состояние детей при клике
|
||||
if (fileItem.IsDirectory && checkBox.IsChecked.HasValue)
|
||||
{
|
||||
foreach (var child in fileItem.Children)
|
||||
{
|
||||
child.IsSelected = checkBox.IsChecked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user