import files from QWEN coder
This commit is contained in:
25
CodeContextGenerator.sln
Normal file
25
CodeContextGenerator.sln
Normal 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
|
||||||
15
CodeContextGenerator/App.config
Normal file
15
CodeContextGenerator/App.config
Normal 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>
|
||||||
13
CodeContextGenerator/App.xaml
Normal file
13
CodeContextGenerator/App.xaml
Normal 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>
|
||||||
8
CodeContextGenerator/App.xaml.cs
Normal file
8
CodeContextGenerator/App.xaml.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CodeContextGenerator
|
||||||
|
{
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
10
CodeContextGenerator/AssemblyInfo.cs
Normal file
10
CodeContextGenerator/AssemblyInfo.cs
Normal 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)
|
||||||
|
)]
|
||||||
26
CodeContextGenerator/CodeContextGenerator.csproj
Normal file
26
CodeContextGenerator/CodeContextGenerator.csproj
Normal 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>
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
CodeContextGenerator/Converters/NullToVisibilityConverter.cs
Normal file
20
CodeContextGenerator/Converters/NullToVisibilityConverter.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
CodeContextGenerator/Models/FileItem.cs
Normal file
60
CodeContextGenerator/Models/FileItem.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
CodeContextGenerator/Properties/Settings.Designer.cs
generated
Normal file
38
CodeContextGenerator/Properties/Settings.Designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
CodeContextGenerator/Properties/Settings.settings
Normal file
9
CodeContextGenerator/Properties/Settings.settings
Normal 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>
|
||||||
191
CodeContextGenerator/Services/FileProcessorService.cs
Normal file
191
CodeContextGenerator/Services/FileProcessorService.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
CodeContextGenerator/Services/ProjectScannerService.cs
Normal file
116
CodeContextGenerator/Services/ProjectScannerService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
344
CodeContextGenerator/ViewModels/MainViewModel.cs
Normal file
344
CodeContextGenerator/ViewModels/MainViewModel.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
119
CodeContextGenerator/Views/MainWindow.xaml
Normal file
119
CodeContextGenerator/Views/MainWindow.xaml
Normal 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>
|
||||||
14
CodeContextGenerator/Views/MainWindow.xaml.cs
Normal file
14
CodeContextGenerator/Views/MainWindow.xaml.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user