Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 830
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 814
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 804
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 789
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "public" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 756
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 730
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 707
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 657
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 618
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 600
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 568
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 533
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0106 Модификатор "private" недопустим для этого элемента. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 511
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS1002 Требуется ";". magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 508
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS1026 Требуется ")" magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 508
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0103 Имя "AddCombinedDataTab" не существует в текущем контексте. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 336
Серьезность Код Описание Проект Файл Строка Состояние подавления
Ошибка (активно) CS0103 Имя "ConvertToCombinedDataTable" не существует в текущем контексте. magn C:\Users\bonia\source\repos\magn\MainWindow.xaml.cs 332


// MainWindow.xaml.cs
using Microsoft.Win32;
using Newtonsoft.Json;
using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace TxtProcessorApp
{
    public partial class MainWindow : Window
    {
        // Dictionaries to store data from files
        private Dictionary<string, List<string[]>> txtFileData = new Dictionary<string, List<string[]>>();
        private Dictionary<string, List<string[]>> magneteFileData = new Dictionary<string, List<string[]>>();

        // Storage for combined data for further editing
        public DataTable combinedTxtDataTable = null;
        public DataTable combinedMagneteDataTable = null;

        public MainWindow()
        {
            InitializeComponent();
        }

        #region File Loading Handlers

        // Handler for loading files
        private async void LoadFiles_Click(object sender, RoutedEventArgs e)
        {
            if (sender is Button button && button.Tag is string fileType)
            {
                string filter = fileType == "txt" ? "Текстовые файлы (*.txt)|*.txt" : "Magnete файлы (*.magnete)|*.magnete";
                OpenFileDialog ofd = new OpenFileDialog
                {
                    Multiselect = true,
                    Filter = filter
                };

                if (ofd.ShowDialog() == true)
                {
                    foreach (var file in ofd.FileNames)
                    {
                        await ProcessFileAsync(file, fileType);
                    }

                    // Update the respective TabControl
                    if (fileType == "txt")
                    {
                        PopulateTabControl(FilesTabControl, txtFileData, CreateTxtDataGrid);
                        combinedTxtDataTable = null; // Reset combined data
                    }
                    else
                    {
                        PopulateTabControl(MagneteFilesTabControl, magneteFileData, CreateMagneteDataGrid);
                        combinedMagneteDataTable = null; // Reset combined data
                    }

                    EditExportButton.IsEnabled = false;
                    StatusTextBlock.Text = $"Загружено {(fileType == "txt" ? txtFileData.Count : magneteFileData.Count)} {(fileType == "txt" ? ".txt" : ".magnete")} файлов.";
                }
            }
        }

        // Universal method for processing files
        private Task ProcessFileAsync(string filePath, string fileType)
        {
            return Task.Run(() =>
            {
                List<string[]> processedLines = new List<string[]>();

                try
                {
                    var lines = File.ReadAllLines(filePath);
                    if (fileType == "txt")
                    {
                        lines = lines.Skip(11).ToArray(); // Skip first 11 lines
                    }

                    foreach (var line in lines)
                    {
                        if (string.IsNullOrWhiteSpace(line))
                            continue;

                        var columns = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        if (columns.Length == 0)
                            continue;

                        // Check the first column
                        if (columns[0].ToLower() == "nan" || string.IsNullOrWhiteSpace(columns[0]))
                            continue;

                        // Add columns based on file type
                        if (fileType == "txt")
                        {
                            // For .txt, skip the first column
                            processedLines.Add(columns.Skip(1).ToArray());
                        }
                        else
                        {
                            // For .magnete, add all columns
                            processedLines.Add(columns);
                        }
                    }

                    // Add processed data to the dictionary
                    string fileName = Path.GetFileName(filePath);
                    string uniqueFileName = GetUniqueFileName(fileName, fileType == "txt" ? txtFileData : magneteFileData);
                    if (fileType == "txt")
                    {
                        lock (txtFileData)
                        {
                            txtFileData[uniqueFileName] = processedLines;
                        }
                    }
                    else
                    {
                        lock (magneteFileData)
                        {
                            magneteFileData[uniqueFileName] = processedLines;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Dispatcher.Invoke(() =>
                        MessageBox.Show($"Ошибка при обработке файла {filePath}:\n{ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error));
                }
            });
        }

        // Method to generate unique file name
        private string GetUniqueFileName(string fileName, Dictionary<string, List<string[]>> existingData)
        {
            string originalFileName = fileName;
            int duplicateCount = 1;
            while (existingData.ContainsKey(fileName))
            {
                fileName = $"{Path.GetFileNameWithoutExtension(originalFileName)}_{duplicateCount}{Path.GetExtension(originalFileName)}";
                duplicateCount++;
            }
            return fileName;
        }

        // Method to populate TabControl
        private void PopulateTabControl(TabControl tabControl, Dictionary<string, List<string[]>> fileData, Func<List<string[]>, DataGrid> createGrid)
        {
            Dispatcher.Invoke(() =>
            {
                tabControl.Items.Clear();
                foreach (var kvp in fileData)
                {
                    TabItem tabItem = new TabItem
                    {
                        Header = kvp.Key,
                        Content = createGrid(kvp.Value)
                    };
                    tabControl.Items.Add(tabItem);
                }
            });
        }

        // Create DataGrid for .txt files
        private DataGrid CreateTxtDataGrid(List<string[]> data)
        {
            if (combinedTxtDataTable == null)
            {
                combinedTxtDataTable = ConvertToDataTable(data, isTxt: true);
            }

            DataGrid dataGrid = new DataGrid
            {
                AutoGenerateColumns = true,
                ItemsSource = combinedTxtDataTable.DefaultView,
                IsReadOnly = true,
                FontFamily = new System.Windows.Media.FontFamily("Consolas"),
                FontSize = 12,
                Margin = new Thickness(5)
            };
            return dataGrid;
        }

        // Create DataGrid for .magnete files
        private DataGrid CreateMagneteDataGrid(List<string[]> data)
        {
            if (combinedMagneteDataTable == null)
            {
                combinedMagneteDataTable = ConvertToDataTable(data, isTxt: false);
            }

            DataGrid dataGrid = new DataGrid
            {
                AutoGenerateColumns = true,
                ItemsSource = combinedMagneteDataTable.DefaultView,
                IsReadOnly = true,
                FontFamily = new System.Windows.Media.FontFamily("Consolas"),
                FontSize = 12,
                Margin = new Thickness(5)
            };
            return dataGrid;
        }

        // Universal method to convert data to DataTable
        private DataTable ConvertToDataTable(List<string[]> data, bool isTxt)
        {
            DataTable dt = new DataTable();
            if (data == null || data.Count == 0)
                return dt;

            if (isTxt)
            {
                dt.Columns.Add("№", typeof(int));
                dt.Columns.Add("BASE-1", typeof(string));
                dt.Columns.Add("Noise", typeof(string));
                dt.Columns.Add("Time", typeof(string));
                dt.Columns.Add("Time UTC", typeof(string));
            }
            else
            {
                // Define columns for .magnete, assuming fixed number of columns
                dt.Columns.Add("Stan", typeof(string));
                dt.Columns.Add("Zeit", typeof(string));
                dt.Columns.Add("Noise", typeof(string));
                dt.Columns.Add("Time", typeof(string));
                dt.Columns.Add("TimeUTC", typeof(string));
            }

            int number = 1;
            foreach (var row in data)
            {
                DataRow dr = dt.NewRow();
                if (isTxt)
                {
                    dr["№"] = number++;
                    dr["BASE-1"] = row.Length > 0 ? row[0] : string.Empty;
                    dr["Noise"] = row.Length > 1 ? row[1] : string.Empty;
                    dr["Time"] = row.Length > 2 ? row[2] : string.Empty;
                    dr["Time UTC"] = row.Length > 3 ? row[3] : string.Empty;
                }
                else
                {
                    dr["Stan"] = row.Length > 0 ? row[0] : string.Empty;
                    dr["Zeit"] = row.Length > 1 ? row[1] : string.Empty;
                    dr["Noise"] = row.Length > 2 ? row[2] : string.Empty;
                    dr["Time"] = row.Length > 3 ? row[3] : string.Empty;
                    dr["TimeUTC"] = row.Length > 4 ? row[4] : string.Empty;
                }
                dt.Rows.Add(dr);
            }

            return dt;
        }

        #endregion

        #region File Combining Handler

        // Handler for Combine Files button
        private async void CombineFiles_Click(object sender, RoutedEventArgs e)
        {
            if (!txtFileData.Any() && !magneteFileData.Any())
            {
                MessageBox.Show("Нет загруженных файлов для объединения.", "Информация", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            // Dialog to select file type to combine
            SelectEditTypeWindow selectWindow = new SelectEditTypeWindow("Выберите тип файлов для объединения:");
            selectWindow.Owner = this;

            if (selectWindow.ShowDialog() == true)
            {
                string selectedOption = selectWindow.SelectedOption;

                if (selectedOption == ".txt файлы" && txtFileData.Any())
                {
                    await CombineTxtFilesAsync();
                }
                else if (selectedOption == ".magnete файлы" && magneteFileData.Any())
                {
                    await CombineMagneteFilesAsync();
                }
                else
                {
                    MessageBox.Show("Выбранная опция недоступна или нет загруженных файлов данного типа.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        // Asynchronous method to combine .txt files
        private Task CombineTxtFilesAsync()
        {
            return Task.Run(() =>
            {
                List<string[]> combinedData = new List<string[]>();
                int lineNumber = 1;

                foreach (var file in txtFileData.Values)
                {
                    foreach (var row in file)
                    {
                        if (row.Length < 3)
                            continue;

                        string secondColumn = row[1];
                        string thirdColumn = row.Length > 1 ? row[2] : string.Empty;
                        string fourthColumn = row.Length > 2 ? row[3] : "0";

                        string timeString = "InvalidNumber";
                        if (double.TryParse(fourthColumn, NumberStyles.Any, CultureInfo.InvariantCulture, out double number))
                        {
                            double divided = number / 24;
                            TimeSpan time = TimeSpan.FromDays(divided);
                            timeString = time.ToString(@"hh\:mm\:ss");
                        }

                        combinedData.Add(new string[]
                        {
                            lineNumber.ToString(),
                            secondColumn,
                            thirdColumn,
                            fourthColumn,
                            timeString
                        });

                        lineNumber++;
                    }
                }

                combinedTxtDataTable = ConvertToCombinedDataTable(combinedData, isTxt: true);

                Dispatcher.Invoke(() =>
                {
                    AddCombinedDataTab(combinedTxtDataTable, ".txt данные объединённые", FilesTabControl);
                    EditExportButton.IsEnabled = true;
                    StatusTextBlock.Text = $"Объединены .txt файлы. Строк: {combinedTxtDataTable.Rows.Count}.";
                });
            });
        }

        // Asynchronous method to combine .magnete files
        private Task CombineMagneteFilesAsync()
        {
            return Task.Run(() =>
            {
                if (!magneteFileData.Any())
                {
                    Dispatcher.Invoke(() =>
                        MessageBox.Show("Нет загруженных .magnete файлов для объединения.", "Информация", MessageBoxButton.OK, MessageBoxImage.Information));
                    return;
                }

                DateTime fixedDate = new DateTime(1980, 1, 6, 0, 0, 0, DateTimeKind.Utc);
                DataTable combinedTable = new DataTable();

                // Define columns
                Dispatcher.Invoke(() =>
                {
                    combinedTable.Columns.Add("DATA", typeof(string));
                    combinedTable.Columns.Add("DATA UTC", typeof(string));
                    combinedTable.Columns.Add("TIME", typeof(string));
                    combinedTable.Columns.Add("TIME UTC", typeof(string));
                    combinedTable.Columns.Add("Долгота WGS", typeof(string));
                    combinedTable.Columns.Add("Широта WGS", typeof(string));
                    combinedTable.Columns.Add("Долгота UTM", typeof(double));
                    combinedTable.Columns.Add("Широта UTM", typeof(double));
                    combinedTable.Columns.Add("№1", typeof(int));
                    combinedTable.Columns.Add("Альтитуда", typeof(string));
                    combinedTable.Columns.Add("№2", typeof(int));
                    combinedTable.Columns.Add("Shark", typeof(string));
                });

                int sequentialNumber = 1;
                List<string> errorMessages = new List<string>();

                foreach (var file in magneteFileData.Values)
                {
                    foreach (var row in file)
                    {
                        DataRow newRow = combinedTable.NewRow();
                        newRow["DATA UTC"] = fixedDate.ToString("dd.MM.yyyy");
                        newRow["TIME"] = row.Length > 0 ? row[0].Trim() : string.Empty;
                        newRow["Широта WGS"] = row.Length > 1 ? row[1].Trim() : string.Empty;
                        newRow["Долгота WGS"] = row.Length > 2 ? row[2].Trim() : string.Empty;
                        newRow["№1"] = sequentialNumber;
                        newRow["№2"] = sequentialNumber;
                        newRow["Альтитуда"] = row.Length > 3 ? row[3].Trim() : string.Empty;
                        newRow["Shark"] = row.Length > 4 ? row[4].Trim() : string.Empty;
                        newRow["Долгота UTM"] = 0.0;
                        newRow["Широта UTM"] = 0.0;

                        string stanValue = row.Length > 0 ? row[0].Trim() : string.Empty;
                        string zeitValue = row.Length > 1 ? row[1].Trim() : string.Empty;
                        string noiseValue = row.Length > 2 ? row[2].Trim() : string.Empty;

                        double longitude, latitude;
                        bool validCoordinates = true;

                        if (!double.TryParse(noiseValue, NumberStyles.Any, CultureInfo.InvariantCulture, out longitude))
                        {
                            string error = $"Не удалось распарсить Долгота WGS='{noiseValue}' в строке: {string.Join("\t", row)}.";
                            errorMessages.Add(error);
                            LogCalculation(error);
                            validCoordinates = false;
                        }

                        if (!double.TryParse(zeitValue, NumberStyles.Any, CultureInfo.InvariantCulture, out latitude))
                        {
                            string error = $"Не удалось распарсить Широта WGS='{zeitValue}' в строке: {string.Join("\t", row)}.";
                            errorMessages.Add(error);
                            LogCalculation(error);
                            validCoordinates = false;
                        }

                        if (validCoordinates)
                        {
                            try
                            {
                                int utmZone = GetUTMZone(longitude);
                                var utmCoordinates = ConvertWGS84ToUTM(longitude, latitude, utmZone);
                                newRow["Долгота UTM"] = utmCoordinates.Easting;
                                newRow["Широта UTM"] = utmCoordinates.Northing;
                            }
                            catch (Exception ex)
                            {
                                string error = $"Ошибка при преобразовании координат (Долгота WGS='{noiseValue}', Широта WGS='{zeitValue}') в строке: {string.Join("\t", row)}. Текст ошибки: {ex.Message}.";
                                errorMessages.Add(error);
                                LogCalculation(error);
                                validCoordinates = false;
                            }
                        }

                        // Handle "Stan" column
                        if (double.TryParse(stanValue, NumberStyles.Any, CultureInfo.InvariantCulture, out double stanSeconds))
                        {
                            if (stanSeconds < 0)
                            {
                                string warning = $"Отрицательное значение TIME='{stanSeconds}' в строке: {string.Join("\t", row)}. Установка даты как фиксированной.";
                                errorMessages.Add(warning);
                                LogCalculation(warning);

                                newRow["DATA"] = fixedDate.ToString("dd.MM.yyyy");
                                newRow["TIME UTC"] = fixedDate.ToString("HH:mm:ss.f");
                            }
                            else
                            {
                                try
                                {
                                    DateTime computedDate = fixedDate.AddSeconds(stanSeconds);
                                    newRow["DATA"] = computedDate.ToString("dd.MM.yyyy");

                                    TimeSpan offsetTime = TimeSpan.FromSeconds(18);
                                    TimeSpan computedTime = (computedDate.TimeOfDay >= offsetTime) ? computedDate.TimeOfDay - offsetTime : TimeSpan.Zero;
                                    double roundedSeconds = Math.Round(computedTime.TotalSeconds, 1, MidpointRounding.AwayFromZero);
                                    TimeSpan roundedTime = TimeSpan.FromSeconds(roundedSeconds);
                                    newRow["TIME UTC"] = roundedTime.ToString(@"hh\:mm\:ss\.f");
                                }
                                catch (Exception ex)
                                {
                                    string error = $"Ошибка при расчёте даты для TIME='{stanSeconds}' в строке: {string.Join("\t", row)}. Текст ошибки: {ex.Message}. Установка даты как фиксированной.";
                                    errorMessages.Add(error);
                                    LogCalculation(error);

                                    newRow["DATA"] = fixedDate.ToString("dd.MM.yyyy");
                                    newRow["TIME UTC"] = fixedDate.ToString("HH:mm:ss.f");
                                }
                            }
                        }
                        else
                        {
                            string error = $"Не удалось распарсить TIME='{stanValue}' в строке: {string.Join("\t", row)}. Установка даты как фиксированной.";
                            errorMessages.Add(error);
                            LogCalculation(error);

                            newRow["DATA"] = fixedDate.ToString("dd.MM.yyyy");
                            newRow["TIME UTC"] = fixedDate.ToString("HH:mm:ss.f");
                        }

                        combinedTable.Rows.Add(newRow);
                        sequentialNumber++;

                        // Log calculations for each row
                        string logMessage = $"TIME: '{stanValue}', ComputedDate: '{newRow["DATA"]}', ComputedTime: '{newRow["TIME UTC"]}'";
                        LogCalculation(logMessage);
                    }
                }

                Dispatcher.Invoke(() =>
                {
                    combinedMagneteDataTable = combinedTable;
                    AddCombinedDataTab(combinedMagneteDataTable, ".magnete данные объединённые", MagneteFilesTabControl);
                    EditExportButton.IsEnabled = true;
                    StatusTextBlock.Text = $"Объединены .magnete файлы. Строк: {combinedMagneteDataTable.Rows.Count}.";

                    if (errorMessages.Any())
                    {
                        string allErrors = string.Join("\n", errorMessages);
                        LogCalculation($"Обнаружены следующие проблемы:\n{allErrors}");
                        MessageBox.Show($"Файлы .magnete объединены с ошибками. Подробности в файле логов.", "Внимание", MessageBoxButton.OK, MessageBoxImage.Warning);
                    }
                    else
                    {
                        MessageBox.Show($"Файлы .magnete успешно объединены. Строк: {combinedMagneteDataTable.Rows.Count}", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                });
            }

            // Method to add a combined data tab
            private void AddCombinedDataTab(DataTable combinedData, string header, TabControl parentTabControl)
            {
                // Check if the combined data tab already exists
                foreach (TabItem tab in parentTabControl.Items)
                {
                    if (tab.Header.ToString() == header)
                        return; // Tab already exists
                }

                // Create DataGrid bound to the combined DataTable
                DataGrid dataGrid = CreateDataGrid(combinedData, isEditable: false);

                TabItem combinedTab = new TabItem
                {
                    Header = header,
                    Content = dataGrid
                };

                parentTabControl.Items.Add(combinedTab);
            }

            // Method to convert combined data to DataTable
            private DataTable ConvertToCombinedDataTable(List<string[]> data, bool isTxt)
            {
                DataTable dt = new DataTable();

                if (isTxt)
                {
                    dt.Columns.Add("№", typeof(int));
                    dt.Columns.Add("BASE-1", typeof(string));
                    dt.Columns.Add("Noise", typeof(string));
                    dt.Columns.Add("Time", typeof(string));
                    dt.Columns.Add("Time UTC", typeof(string));
                }

                foreach (var row in data)
                {
                    DataRow dr = dt.NewRow();
                    if (isTxt)
                    {
                        dr["№"] = int.Parse(row[0]);
                        dr["BASE-1"] = row[1];
                        dr["Noise"] = row[2];
                        dr["Time"] = row[3];
                        dr["Time UTC"] = row[4];
                    }
                    dt.Rows.Add(dr);
                }

                return dt;
            }

            #endregion

            #region Edit and Export Handler

            // Handler for Edit and Export button
            private void EditAndExport_Click(object sender, RoutedEventArgs e)
            {
                if (combinedTxtDataTable == null && combinedMagneteDataTable == null)
                {
                    MessageBox.Show("Нет объединённых данных для редактирования.", "Информация", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                // Create and open a dialog to select the data type to edit
                SelectEditTypeWindow selectWindow = new SelectEditTypeWindow("Выберите данные для редактирования:");
                selectWindow.Owner = this;

                if (selectWindow.ShowDialog() == true)
                {
                    string selectedOption = selectWindow.SelectedOption;

                    if (selectedOption == ".txt файлы" && combinedTxtDataTable != null)
                    {
                        OpenEditWindow(combinedTxtDataTable, "Редактирование .txt данных");
                    }
                    else if (selectedOption == ".magnete файлы" && combinedMagneteDataTable != null)
                    {
                        OpenEditWindow(combinedMagneteDataTable, "Редактирование .magnete данных");
                    }
                    else
                    {
                        MessageBox.Show("Выбранная опция недоступна или данные отсутствуют.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }

            // Method to open the edit window
            private void OpenEditWindow(DataTable dataTable, string windowTitle)
            {
                EditWindow editWindow = new EditWindow(dataTable)
                {
                    Title = windowTitle,
                    Owner = this
                };
                editWindow.ShowDialog();

                // After editing, refresh the DataGrid in case of changes
                RefreshCombinedDataTabs();
            }

            #endregion

            #region Project Handling

            // Handler for Save Project button
            private async void SaveProject_Click(object sender, RoutedEventArgs e)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog
                {
                    Filter = "Magnte Project Files (*.magn)|*.magn",
                    DefaultExt = "magn",
                    FileName = "project.magn"
                };

                if (saveFileDialog.ShowDialog() == true)
                {
                    ProjectData project = new ProjectData
                    {
                        TxtFileData = this.txtFileData,
                        MagneteFileData = this.magneteFileData,
                        CombinedTxtDataTable = this.combinedTxtDataTable,
                        CombinedMagneteDataTable = this.combinedMagneteDataTable
                    };

                    try
                    {
                        // Asynchronously serialize the object to JSON
                        string json = await Task.Run(() => JsonConvert.SerializeObject(project, Formatting.Indented, new JsonSerializerSettings
                        {
                            PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                        }));
                        await File.WriteAllTextAsync(saveFileDialog.FileName, json, System.Text.Encoding.UTF8);
                        StatusTextBlock.Text = $"Проект сохранён: {saveFileDialog.FileName}";
                        MessageBox.Show("Проект успешно сохранён.", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"Ошибка при сохранении проекта:\n{ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }

            // Handler for Load Project button
            private async void LoadProject_Click(object sender, RoutedEventArgs e)
            {
                OpenFileDialog openFileDialog = new OpenFileDialog
                {
                    Filter = "Magnte Project Files (*.magn)|*.magn",
                    DefaultExt = "magn"
                };

                if (openFileDialog.ShowDialog() == true)
                {
                    try
                    {
                        string json = await File.ReadAllTextAsync(openFileDialog.FileName, System.Text.Encoding.UTF8);
                        ProjectData project = JsonConvert.DeserializeObject<ProjectData>(json);

                        if (project != null)
                        {
                            // Load .txt data
                            this.txtFileData = project.TxtFileData ?? new Dictionary<string, List<string[]>>();
                            PopulateTabControl(FilesTabControl, txtFileData, CreateTxtDataGrid);

                            // Load .magnete data
                            this.magneteFileData = project.MagneteFileData ?? new Dictionary<string, List<string[]>>();
                            PopulateTabControl(MagneteFilesTabControl, magneteFileData, CreateMagneteDataGrid);

                            // Load combined DataTables
                            this.combinedTxtDataTable = project.CombinedTxtDataTable;
                            this.combinedMagneteDataTable = project.CombinedMagneteDataTable;

                            // Update the combined data tabs
                            RefreshCombinedDataTabs();

                            EditExportButton.IsEnabled = combinedTxtDataTable != null || combinedMagneteDataTable != null;

                            StatusTextBlock.Text = $"Проект загружен: {openFileDialog.FileName}";
                            MessageBox.Show("Проект успешно загружен.", "Успех", MessageBoxButton.OK, MessageBoxImage.Information);
                        }
                        else
                        {
                            MessageBox.Show("Не удалось загрузить данные проекта.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"Ошибка при загрузке проекта:\n{ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }

            #endregion

            #region Graph Window Handler

            // Handler for Show Graphs button
            private void ShowGraphs_Click(object sender, RoutedEventArgs e)
            {
                if (combinedTxtDataTable == null && combinedMagneteDataTable == null)
                {
                    MessageBox.Show("Нет объединённых данных для построения графиков.", "Информация", MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                // Создание экземпляра GraphWindow
                GraphWindow graphWindow = new GraphWindow(combinedTxtDataTable, combinedMagneteDataTable)
                {
                    Owner = this
                };

                // Подписка на событие DataModified
                graphWindow.DataModified += RefreshCombinedDataTabs;

                graphWindow.ShowDialog();

                // После закрытия GraphWindow обновляем TabControl с объединёнными данными
                RefreshCombinedDataTabs();

                StatusTextBlock.Text = $"Данные обновлены после редактирования графиков.";
            }

            // Method to refresh combined data tabs
            public void RefreshCombinedDataTabs()
            {
                Dispatcher.Invoke(() =>
                {
                    // Refresh .txt combined tab
                    foreach (TabItem tab in FilesTabControl.Items)
                    {
                        if (tab.Header.ToString().Contains("объединённые") && combinedTxtDataTable != null)
                        {
                            var newDataGrid = CreateTxtDataGrid(ConvertDataTableToList(combinedTxtDataTable));
                            tab.Content = newDataGrid;
                        }
                    }

                    // Refresh .magnete combined tab
                    foreach (TabItem tab in MagneteFilesTabControl.Items)
                    {
                        if (tab.Header.ToString().Contains("объединённые") && combinedMagneteDataTable != null)
                        {
                            var newDataGrid = CreateMagneteDataGrid(ConvertDataTableToList(combinedMagneteDataTable));
                            tab.Content = newDataGrid;
                        }
                    }

                    EditExportButton.IsEnabled = combinedTxtDataTable != null || combinedMagneteDataTable != null;
                });
            }

            #endregion

            #region Graph Combining Helper Methods

            // Method for logging calculations and errors
            private void LogCalculation(string message, string logFileName = "calculation_log.txt")
            {
                string logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, logFileName);
                try
                {
                    File.AppendAllText(logFilePath, $"{DateTime.Now}: {message}{Environment.NewLine}");
                }
                catch (Exception ex)
                {
                    Dispatcher.Invoke(() =>
                        MessageBox.Show($"Не удалось записать лог: {ex.Message}", "Ошибка логирования", MessageBoxButton.OK, MessageBoxImage.Error));
                }
            }

            // Method to determine UTM zone based on longitude
            private int GetUTMZone(double longitude)
            {
                if (longitude < -180 || longitude > 180)
                    throw new ArgumentOutOfRangeException("Долгота должна быть в диапазоне от -180 до 180 градусов.");

                int zone = (int)Math.Floor((longitude + 180) / 6) + 1;
                return zone;
            }

            // Method to convert WGS84 coordinates to UTM
            private (double Easting, double Northing) ConvertWGS84ToUTM(double longitude, double latitude, int utmZone)
            {
                var wgs84 = GeographicCoordinateSystem.WGS84;
                var utmCS = ProjectedCoordinateSystem.WGS84_UTM(utmZone, latitude >= 0);
                var transformFactory = new CoordinateTransformationFactory();
                var transformation = transformFactory.CreateFromCoordinateSystems(wgs84, utmCS);
                double[] fromPoint = new double[] { longitude, latitude };
                double[] toPoint = transformation.MathTransform.Transform(fromPoint);
                return (toPoint[0], toPoint[1]);
            }

            #endregion

            #region Combined Data Binding

            // Create DataGrid bound to DataTable
            private DataGrid CreateDataGrid(DataTable dataTable, bool isEditable)
            {
                DataGrid dataGrid = new DataGrid
                {
                    AutoGenerateColumns = true,
                    ItemsSource = dataTable.DefaultView,
                    IsReadOnly = !isEditable,
                    FontFamily = new System.Windows.Media.FontFamily("Consolas"),
                    FontSize = 12,
                    Margin = new Thickness(5)
                };
                return dataGrid;
            }

            #endregion

            #region Helper Methods

            // Method to convert DataTable to List<string[]>
            private List<string[]> ConvertDataTableToList(DataTable table)
            {
                var list = new List<string[]>();
                foreach (DataRow row in table.Rows)
                {
                    if (row.RowState != DataRowState.Deleted)
                    {
                        var rowData = new string[table.Columns.Count];
                        for (int i = 0; i < table.Columns.Count; i++)
                        {
                            rowData[i] = row[i]?.ToString() ?? string.Empty;
                        }
                        list.Add(rowData);
                    }
                }
                return list;
            }

            #endregion
        }
    }
}