import files from QWEN coder

This commit is contained in:
2025-12-10 17:35:57 +05:00
parent d8ad4533d4
commit 2785e1749a
16 changed files with 1032 additions and 0 deletions

25
CodeContextGenerator.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36717.8 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeContextGenerator", "CodeContextGenerator\CodeContextGenerator.csproj", "{F8633901-A03B-46D2-9A44-4C951DD1714C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F8633901-A03B-46D2-9A44-4C951DD1714C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8633901-A03B-46D2-9A44-4C951DD1714C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8633901-A03B-46D2-9A44-4C951DD1714C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8633901-A03B-46D2-9A44-4C951DD1714C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4A67EDD8-1F3E-4D80-9EDB-CA793665319C}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="CodeContextGenerator.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<CodeContextGenerator.Settings1>
<setting name="LastProjectPath" serializeAs="String">
<value />
</setting>
</CodeContextGenerator.Settings1>
</userSettings>
</configuration>

View File

@@ -0,0 +1,13 @@
<Application
x:Class="CodeContextGenerator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:CodeContextGenerator.Converters"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -0,0 +1,8 @@
using System.Windows;
namespace CodeContextGenerator
{
public partial class App : Application
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace CodeContextGenerator.Converters
{
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace CodeContextGenerator.Converters
{
public class NullToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace CodeContextGenerator.Models
{
public class FileItem : INotifyPropertyChanged
{
public string Name { get; set; }
public string FullName { get; set; }
public bool IsDirectory { get; set; }
public ObservableCollection<FileItem> Children { get; set; } = new ObservableCollection<FileItem>();
public FileItem Parent { get; set; }
private bool? _isSelected;
public bool? IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged();
UpdateParentSelection();
UpdateChildrenSelection(value);
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void UpdateParentSelection()
{
if (Parent == null) return;
var children = Parent.Children.ToList();
var allSelected = children.All(c => c.IsSelected == true);
var noneSelected = children.All(c => c.IsSelected == false);
Parent.IsSelected = allSelected ? true : (noneSelected ? false : null);
Parent.UpdateParentSelection();
}
private void UpdateChildrenSelection(bool? value)
{
if (!IsDirectory || !value.HasValue) return;
foreach (var child in Children)
{
child.IsSelected = value;
}
}
}
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Этот код создан программой.
// Исполняемая версия:4.0.30319.42000
//
// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
// повторной генерации кода.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CodeContextGenerator.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string LastProjectPath {
get {
return ((string)(this["LastProjectPath"]));
}
set {
this["LastProjectPath"] = value;
}
}
}
}

View File

@@ -0,0 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="CodeContextGenerator" GeneratedClassName="Settings1">
<Profiles />
<Settings>
<Setting Name="LastProjectPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@@ -0,0 +1,191 @@
using System.Text;
using System.Text.RegularExpressions;
namespace CodeContextGenerator.Services
{
public static class FileProcessorService
{
public static string ProcessFileContent(string content, string fileName)
{
if (fileName.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase))
{
return RemoveXamlComments(content);
}
else if (fileName.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
{
return RemoveCSharpComments(content);
}
return content;
}
private static string RemoveXamlComments(string content)
{
// Удаляем XAML комментарии <!-- ... -->
return Regex.Replace(content, @"<!--.*?-->", "", RegexOptions.Singleline | RegexOptions.Compiled);
}
private static string RemoveCSharpComments(string content)
{
var sb = new StringBuilder();
var lines = content.Split('\n');
foreach (var line in lines)
{
string processedLine = ProcessCSharpLine(line);
sb.AppendLine(processedLine);
}
return sb.ToString();
}
private static string ProcessCSharpLine(string line)
{
if (string.IsNullOrWhiteSpace(line))
return line;
// Удаляем XML-комментарии ///
if (line.TrimStart().StartsWith("///", StringComparison.Ordinal))
return string.Empty;
// Проверяем на однострочные комментарии
int commentIndex = line.IndexOf("//", StringComparison.Ordinal);
if (commentIndex >= 0)
{
// Проверяем, не находится ли // внутри строки
bool inString = false;
bool inChar = false;
bool escapeNext = false;
for (int i = 0; i < commentIndex; i++)
{
char c = line[i];
if (escapeNext)
{
escapeNext = false;
continue;
}
if (c == '\\')
{
escapeNext = true;
continue;
}
if (!inChar && c == '"')
{
inString = !inString;
continue;
}
if (!inString && c == '\'')
{
inChar = !inChar;
continue;
}
}
if (!inString && !inChar)
{
return line.Substring(0, commentIndex).TrimEnd();
}
}
return line.TrimEnd();
}
public static string RemoveMultiLineComments(string content)
{
var result = new StringBuilder();
var stack = new Stack<int>();
bool inComment = false;
bool inString = false;
bool inChar = false;
bool escapeNext = false;
for (int i = 0; i < content.Length; i++)
{
char c = content[i];
if (escapeNext)
{
escapeNext = false;
if (!inComment) result.Append(c);
continue;
}
if (c == '\\' && (inString || inChar))
{
escapeNext = true;
if (!inComment) result.Append(c);
continue;
}
// Обработка строковых литералов
if (!inComment)
{
if (!inString && !inChar && c == '"')
{
inString = true;
result.Append(c);
continue;
}
if (!inString && !inChar && c == '\'')
{
inChar = true;
result.Append(c);
continue;
}
if (inString && c == '"')
{
inString = false;
result.Append(c);
continue;
}
if (inChar && c == '\'')
{
inChar = false;
result.Append(c);
continue;
}
}
if (inString || inChar)
{
result.Append(c);
continue;
}
// Обработка многострочных комментариев
if (i < content.Length - 1)
{
if (!inComment && c == '/' && content[i + 1] == '*')
{
inComment = true;
stack.Push(i);
i++; // Пропускаем следующий символ
continue;
}
if (inComment && c == '*' && content[i + 1] == '/')
{
inComment = false;
stack.Pop();
i++; // Пропускаем следующий символ
continue;
}
}
if (!inComment)
{
result.Append(c);
}
}
return result.ToString();
}
}
}

View File

@@ -0,0 +1,116 @@
using System.IO;
using CodeContextGenerator.Models;
namespace CodeContextGenerator.Services;
public static class ProjectScannerService
{
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)
{
var rootItem = new FileItem
{
Name = Path.GetFileName(rootPath),
FullName = rootPath,
IsDirectory = true,
IsSelected = false
};
await BuildDirectoryTreeAsync(rootPath, rootItem, progress, cancellationToken);
return rootItem;
}
private static async Task BuildDirectoryTreeAsync(string path, FileItem parentItem, IProgress<int> progress = null, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
var directories = Directory.GetDirectories(path)
.Where(d => !ExcludedDirectories.Any(ex => d.EndsWith(ex, StringComparison.OrdinalIgnoreCase)))
.ToList();
var files = Directory.GetFiles(path)
.Where(f => IncludedExtensions.Any(ext => f.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
.ToList();
int totalItems = directories.Count + files.Count;
int processedItems = 0;
// Обрабатываем поддиректории
foreach (var dir in directories)
{
cancellationToken.ThrowIfCancellationRequested();
var dirName = Path.GetFileName(dir);
var dirItem = new FileItem
{
Name = dirName,
FullName = dir,
IsDirectory = true,
Parent = parentItem,
IsSelected = false
};
await BuildDirectoryTreeAsync(dir, dirItem, progress, cancellationToken);
// Добавляем директорию только если в ней есть файлы или поддиректории с файлами
if (dirItem.Children.Any())
{
parentItem.Children.Add(dirItem);
}
processedItems++;
progress?.Report((int)((processedItems * 100.0) / totalItems));
}
// Обрабатываем файлы
foreach (var file in files)
{
cancellationToken.ThrowIfCancellationRequested();
var fileItem = new FileItem
{
Name = Path.GetFileName(file),
FullName = file,
IsDirectory = false,
Parent = parentItem,
IsSelected = false
};
parentItem.Children.Add(fileItem);
processedItems++;
progress?.Report((int)((processedItems * 100.0) / totalItems));
}
}
catch (Exception ex)
{
// Логируем ошибку, но продолжаем работу
Console.WriteLine($"Error scanning directory {path}: {ex.Message}");
}
}
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);
}
}
}

View File

@@ -0,0 +1,344 @@
using CodeContextGenerator.Models;
using CodeContextGenerator.Services;
using Microsoft.Win32;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace CodeContextGenerator.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
private FileItem _rootDirectory;
private string _selectedFolderPath;
private bool _isProcessing;
private int _progressValue;
private string _progressText;
private CancellationTokenSource _cancellationTokenSource;
private string _lastProjectPath;
public FileItem RootDirectory
{
get => _rootDirectory;
set
{
_rootDirectory = value;
OnPropertyChanged();
}
}
public string SelectedFolderPath
{
get => _selectedFolderPath;
set
{
_selectedFolderPath = value;
OnPropertyChanged();
}
}
public bool IsProcessing
{
get => _isProcessing;
set
{
_isProcessing = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanSelectFolder));
OnPropertyChanged(nameof(CanGenerate));
}
}
public int ProgressValue
{
get => _progressValue;
set
{
_progressValue = value;
OnPropertyChanged();
}
}
public string ProgressText
{
get => _progressText;
set
{
_progressText = value;
OnPropertyChanged();
}
}
public bool CanSelectFolder => !IsProcessing;
public bool CanGenerate => !IsProcessing && RootDirectory != null && HasSelectedFiles(RootDirectory);
public ICommand SelectFolderCommand { get; }
public ICommand GenerateCommand { get; }
public ICommand CancelCommand { get; }
public ICommand ExitCommand { get; }
public MainViewModel()
{
SelectFolderCommand = new RelayCommand(SelectFolderAsync);
GenerateCommand = new RelayCommand(GenerateFileAsync, _ => CanGenerate);
CancelCommand = new RelayCommand(CancelProcessing, _ => IsProcessing);
ExitCommand = new RelayCommand(_ => Application.Current.Shutdown());
LoadSettings();
}
private bool HasSelectedFiles(FileItem item)
{
if (item.IsSelected == true && !item.IsDirectory)
return true;
foreach (var child in item.Children)
{
if (HasSelectedFiles(child))
return true;
}
return false;
}
private async void SelectFolderAsync(object parameter)
{
if (!CanSelectFolder) return;
var dialog = new OpenFileDialog
{
Title = "Выберите файл проекта или папку",
CheckFileExists = false,
CheckPathExists = true,
FileName = "dummy",
Filter = "Проекты C# (*.csproj)|*.csproj|Все файлы (*.*)|*.*"
};
if (!string.IsNullOrEmpty(_lastProjectPath) && Directory.Exists(_lastProjectPath))
{
dialog.InitialDirectory = _lastProjectPath;
}
bool? result = dialog.ShowDialog();
if (result == true)
{
string selectedPath = dialog.FileName;
string projectDirectory = Path.GetDirectoryName(selectedPath);
if (!string.IsNullOrEmpty(projectDirectory))
{
_lastProjectPath = projectDirectory;
SaveSettings();
await LoadProjectDirectoryAsync(projectDirectory);
}
}
}
private async Task LoadProjectDirectoryAsync(string projectDirectory)
{
IsProcessing = true;
ProgressText = "Сканирование проекта...";
ProgressValue = 0;
try
{
SelectedFolderPath = projectDirectory;
var progress = new Progress<int>(value =>
{
ProgressValue = value;
ProgressText = $"Сканирование: {value}%";
});
_cancellationTokenSource = new CancellationTokenSource();
RootDirectory = await ProjectScannerService.ScanProjectDirectoryAsync(
projectDirectory,
progress,
_cancellationTokenSource.Token
);
ProgressText = "Сканирование завершено";
}
catch (OperationCanceledException)
{
ProgressText = "Сканирование отменено";
RootDirectory = null;
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при сканировании проекта: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
RootDirectory = null;
}
finally
{
IsProcessing = false;
}
}
private async void GenerateFileAsync(object parameter)
{
if (!CanGenerate || RootDirectory == null) return;
var selectedFiles = ProjectScannerService.GetSelectedFiles(RootDirectory);
if (selectedFiles.Count == 0)
{
MessageBox.Show("Пожалуйста, выберите хотя бы один файл для обработки.", "Предупреждение", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var saveDialog = new SaveFileDialog
{
Title = "Сохранить контекстный файл",
Filter = "Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*",
FileName = $"{Path.GetFileName(SelectedFolderPath)}_context.txt",
DefaultExt = ".txt"
};
if (!string.IsNullOrEmpty(_lastProjectPath) && Directory.Exists(_lastProjectPath))
{
saveDialog.InitialDirectory = _lastProjectPath;
}
bool? result = saveDialog.ShowDialog();
if (result == true)
{
IsProcessing = true;
ProgressText = "Генерация контекстного файла...";
ProgressValue = 0;
try
{
_cancellationTokenSource = new CancellationTokenSource();
var progress = new Progress<int>(value =>
{
ProgressValue = value;
ProgressText = $"Генерация: {value}%";
});
await GenerateContextFileAsync(selectedFiles, saveDialog.FileName, progress, _cancellationTokenSource.Token);
MessageBox.Show($"Файл успешно создан:\n{saveDialog.FileName}", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (OperationCanceledException)
{
ProgressText = "Генерация отменена";
}
catch (IOException ex)
{
MessageBox.Show($"Ошибка доступа к файлу: {ex.Message}\nПожалуйста, закройте файлы или предоставьте необходимые права доступа.", "Ошибка доступа", MessageBoxButton.OK, MessageBoxImage.Error);
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка при генерации файла: {ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
IsProcessing = false;
}
}
}
private async Task GenerateContextFileAsync(List<string> selectedFiles, string outputPath, IProgress<int> progress, CancellationToken cancellationToken)
{
var outputContent = new StringBuilder();
int totalFiles = selectedFiles.Count;
int processedFiles = 0;
foreach (var filePath in selectedFiles)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
string relativePath = Path.GetRelativePath(SelectedFolderPath, filePath);
string fileContent = await File.ReadAllTextAsync(filePath, Encoding.UTF8);
// Обработка комментариев
fileContent = FileProcessorService.ProcessFileContent(fileContent, Path.GetFileName(filePath));
fileContent = FileProcessorService.RemoveMultiLineComments(fileContent);
outputContent.AppendLine($"=== Файл: {relativePath} ===");
outputContent.AppendLine(fileContent);
outputContent.AppendLine(); // Пустая строка между файлами
processedFiles++;
int progressValue = (int)((processedFiles * 100.0) / totalFiles);
progress?.Report(progressValue);
}
catch (IOException ex)
{
// Если файл заблокирован или недоступен - останавливаем процесс
throw new IOException($"Файл '{Path.GetFileName(filePath)}' заблокирован или недоступен: {ex.Message}", ex);
}
}
// Сохраняем результат с кодировкой UTF-8 с BOM для максимальной совместимости
var encoding = new UTF8Encoding(true); // true для BOM
await File.WriteAllTextAsync(outputPath, outputContent.ToString(), encoding);
}
private void CancelProcessing(object parameter)
{
_cancellationTokenSource?.Cancel();
}
private void LoadSettings()
{
try
{
_lastProjectPath = Properties.Settings.Default.LastProjectPath;
}
catch
{
_lastProjectPath = null;
}
}
private void SaveSettings()
{
try
{
Properties.Settings.Default.LastProjectPath = _lastProjectPath;
Properties.Settings.Default.Save();
}
catch
{
// Игнорируем ошибки сохранения настроек
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler? CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
}

View File

@@ -0,0 +1,119 @@
<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">
<Window.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</Window.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<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="Выберите папку проекта:" />
<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"
VerticalAlignment="Center"
Text="{Binding SelectedFolderPath}"
TextWrapping="Wrap" />
</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}}">
<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>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</ScrollViewer>
</Border>
<ProgressBar
Grid.Row="3"
Height="20"
Margin="0,10,0,10"
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}" />
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,14 @@
using System.Windows;
using CodeContextGenerator.ViewModels;
namespace CodeContextGenerator.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
}