using System.ComponentModel; using System.Windows.Controls; using System.Windows.Input; using Ookii.Dialogs.Wpf; using System.Collections.ObjectModel; using System.Windows.Threading; using CtrEditor.ObjetosSim; using CtrEditor.Siemens; using System.IO; using Newtonsoft.Json; using System.Windows; using CtrEditor.Simulacion; using System.Diagnostics; using System.Reflection; using CommunityToolkit.Mvvm.ComponentModel; using Xceed.Wpf.Toolkit.PropertyGrid; using CtrEditor.ObjetosSim.Extraccion_Datos; using ClosedXML.Excel; using CtrEditor.PopUps; using System.Windows.Data; namespace CtrEditor { public partial class MainViewModel : ObservableObject { public Stopwatch stopwatch_Sim; private double stopwatch_SimPLC_last; private double stopwatch_SimModel_last; private float TiempoDesdeStartSimulacion; private bool Debug_SimulacionCreado = false; public SimulationManagerFP simulationManager = new SimulationManagerFP(); private readonly DispatcherTimer _timerSimulacion; public Canvas MainCanvas; [ObservableProperty] private DatosDeTrabajo datosDeTrabajo; [ObservableProperty] private ObservableCollection listaImagenes; // Publicación de las claves del diccionario [ObservableProperty] public ObservableCollection listaOsBase; public ICommand StartSimulationCommand { get; } public ICommand StopSimulationCommand { get; } public ICommand ItemDoubleClickCommand { get; private set; } public ICommand TBStartSimulationCommand { get; } public ICommand TBStopSimulationCommand { get; } public ICommand TBSaveCommand { get; } public ICommand TBConnectPLCCommand { get; } public ICommand TBDisconnectPLCCommand { get; } public ICommand TBExtractTagsCommand { get; } public ICommand TBEliminarUserControlCommand { get; } public ICommand TBDuplicarUserControlCommand { get; } public ICommand OpenWorkDirectoryCommand { get; } public ICommand TBEliminarTodosCommand { get; } public ICommand TBEliminarAutoCreatedCommand { get; } public ICommand TBEliminarClonedCommand { get; } public ICommand TBAssingPagesCommand { get; } public ICommand TBMultiPageExtractTagsCommand { get; } public ICommand TBMultiPageAnalizeCommand { get; } // Evento que se dispara cuando se selecciona una nueva imagen public event EventHandler ImageSelected; public event EventHandler TickSimulacion; // Propiedades private bool habilitarEliminarUserControl; private MainWindow mainWindow; public MainWindow MainWindow { get => mainWindow; set => mainWindow = value; } [ObservableProperty] public ICollectionView vistaFiltrada; [ObservableProperty] private float canvasLeft; [ObservableProperty] private float canvasTop; [ObservableProperty] private bool isSimulationRunning; partial void OnIsSimulationRunningChanged(bool value) { CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado } [ObservableProperty] private bool isConnected; partial void OnIsConnectedChanged(bool value) { CommandManager.InvalidateRequerySuggested(); } public string directorioTrabajo { get => EstadoPersistente.Instance.directorio; set { if (value != null) { EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado DatosDeTrabajo.CargarImagenes(); ListaImagenes = new ObservableCollection(DatosDeTrabajo.Imagenes.Keys); // Actualizar claves SelectedImage = null; var x = ListaImagenes.FirstOrDefault(o => o == EstadoPersistente.Instance.imagen, null); if (EstadoPersistente.Instance.imagen != null && EstadoPersistente.Instance.imagen.Length > 0 && x != null) SelectedImage = EstadoPersistente.Instance.imagen; else if (ListaImagenes.FirstOrDefault() != null) SelectedImage = ListaImagenes.FirstOrDefault(); OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad OnPropertyChanged(nameof(ListaImagenes)); // Notificar que la lista de imágenes ha cambiado } } } [ObservableProperty] private PLCViewModel pLCViewModel; [ObservableProperty] private string selectedImage; partial void OnSelectedImageChanged(string value) { if (value != null) { StopSimulation(); // SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen LoadStateObjetosSimulables(); EstadoPersistente.Instance.imagen = value; EstadoPersistente.Instance.GuardarEstado(); } } [ObservableProperty] private osBase selectedItemOsList; partial void OnSelectedItemOsListChanged(osBase value) { if (value != null) habilitarEliminarUserControl = true; else habilitarEliminarUserControl = false; } [ObservableProperty] public ObjetosSimulablesFilterTypes osListFilter; [ObservableProperty] private TipoSimulable selectedItem; public ICollectionView ObjetosSimulablesFiltered { get; } public ICollectionView ObjetosSimulablesAllPages { get; } [ObservableProperty] public ObservableCollection objetosSimulables; partial void OnObjetosSimulablesChanged(ObservableCollection value) { VistaFiltrada = CollectionViewSource.GetDefaultView(ObjetosSimulables); VistaFiltrada.Filter = FiltrarObjetos; ObjetosSimulables.CollectionChanged += (s, e) => VistaFiltrada.Refresh(); } // // Constructor // public MainViewModel() { OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory); datosDeTrabajo = new DatosDeTrabajo(); osListFilter = new ObjetosSimulablesFilterTypes(); osListFilter.PropertyChanged += OsListFilter_PropertyChanged; ObjetosSimulables = new ObservableCollection(); ListaOsBase = new ObservableCollection(); // Inicializa el PLCViewModel PLCViewModel = new PLCViewModel(); PLCViewModel.RefreshEvent += OnRefreshEvent; InitializeTipoSimulableList(); ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick); _timerSimulacion = new DispatcherTimer(); _timerSimulacion.Interval = TimeSpan.FromMilliseconds(1); // ajusta el intervalo según sea necesario _timerSimulacion.Tick += OnTickSimulacion; StartSimulationCommand = new RelayCommand(StartSimulation); StopSimulationCommand = new RelayCommand(StopSimulation); TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning); TBStopSimulationCommand = new RelayCommand(StopSimulation, () => IsSimulationRunning); TBSaveCommand = new RelayCommand(Save); TBConnectPLCCommand = new RelayCommand(ConnectPLC, () => !IsConnected); TBDisconnectPLCCommand = new RelayCommand(DisconnectPLC, () => IsConnected); TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl); TBDuplicarUserControlCommand = new RelayCommand(DuplicarUserControl, () => habilitarEliminarUserControl); TBExtractTagsCommand = new RelayCommand(ExtraerTags); TBEliminarTodosCommand = new RelayCommand(EliminarTodosCommand); TBEliminarAutoCreatedCommand = new RelayCommand(EliminarAutoCreatedCommand); TBEliminarClonedCommand = new RelayCommand(EliminarClonedCommand); TBAssingPagesCommand = new RelayCommand(AssingPagesCommand); TBMultiPageExtractTagsCommand = new RelayCommand(MultiPageExtractTagsCommand); TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand); stopwatch_Sim = new Stopwatch(); stopwatch_Sim.Start(); } private void OsListFilter_PropertyChanged(object? sender, PropertyChangedEventArgs e) { VistaFiltrada.Refresh(); } private bool FiltrarObjetos(object item) { var objeto = item as osBase; return (objeto.Cloned == osListFilter.Cloned) && (objeto.Enable_On_All_Pages == osListFilter.Enable_On_All_Pages) && (objeto.Show_On_This_Page == osListFilter.Show_On_This_Page); } public void LoadInitialData() { // Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected" directorioTrabajo = EstadoPersistente.Instance.directorio; } // Crear un nuevo Objeto private void ExecuteDoubleClick(object parameter) { if (parameter is TipoSimulable tipoSimulable) { CrearObjetoSimulableEnCentroCanvas(tipoSimulable.Tipo); } } public void CrearObjetoSimulableEnCentroCanvas(Type tipoSimulable) { var CentroCanvas = MainWindow.ObtenerCentroCanvasMeters(); CrearObjetoSimulable(tipoSimulable, CentroCanvas.X, CentroCanvas.Y); } public osBase CrearObjetoSimulable(Type tipoSimulable, float Left, float Top) { // Crear una nueva instancia del osBase correspondiente osBase? NuevoOsBase = UserControlFactory.GetInstanceForType(tipoSimulable); NuevoOsBase.Left = Left; NuevoOsBase.Top = Top; if (NuevoOsBase != null) { if (CrearUserControlDesdeObjetoSimulable(NuevoOsBase)) // Añadir el nuevo osBase a la colección de objetos simulables ObjetosSimulables.Add(NuevoOsBase); } return NuevoOsBase; } // Crear UserControl desde osBase : Nuevo o desde Deserealizacion private bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto) { Type tipoObjeto = osObjeto.GetType(); // Obtén el UserControl correspondiente para el tipo de objeto UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto); if (userControl != null) { // Asignar los datos al UserControl UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager); osObjeto._mainViewModel = this; if (osObjeto.Id == null) // Para los objetos salvados antes de usar UniqueID osObjeto.Id = new UniqueId().ObtenerNuevaID(); MainWindow.AgregarRegistrarUserControlCanvas(userControl); return true; } return false; } public void RemoverObjetoSimulable(osBase osObjeto) { if (osObjeto != null && ObjetosSimulables.Contains(osObjeto)) { ObjetosSimulables.Remove(osObjeto); if (osObjeto.VisualRepresentation != null) MainWindow.EliminarUserControlDelCanvas(osObjeto.VisualRepresentation); } } private void DuplicarUserControl() { if (SelectedItemOsList is osBase objDuplicar) DuplicarObjeto(objDuplicar, 0.5f, 0.5f); } public osBase DuplicarObjeto(osBase objDuplicar, float OffsetX, float OffsetY) { StopSimulation(); DisconnectPLC(); osBase? NuevoObjetoDuplicado = null; objDuplicar.SalvarDatosNoSerializables(); var settings = new JsonSerializerSettings { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.All }; try { // Serializar var serializedData = JsonConvert.SerializeObject(objDuplicar, settings); // Duplicar NuevoObjetoDuplicado = JsonConvert.DeserializeObject(serializedData, settings); if (NuevoObjetoDuplicado != null) { NuevoObjetoDuplicado.Id.ObtenerNuevaID(); string nombre = NuevoObjetoDuplicado.Nombre + "_" + NuevoObjetoDuplicado.Id.Value; NuevoObjetoDuplicado.Nombre = nombre; NuevoObjetoDuplicado.Left += OffsetX; NuevoObjetoDuplicado.Top += OffsetY; ObjetosSimulables.Add(NuevoObjetoDuplicado); CrearUserControlDesdeObjetoSimulable(NuevoObjetoDuplicado); } } catch { // Log error or handle it accordingly } finally { objDuplicar.RestaurarDatosNoSerializables(); } return NuevoObjetoDuplicado; } private void EliminarUserControl() { if (SelectedItemOsList is osBase objEliminar) { RemoverObjetoSimulable(objEliminar); } } private void EliminarTodosCommand() { var objetosSimulablesCopy = new List(ObjetosSimulables); foreach (var obj in objetosSimulablesCopy) RemoverObjetoSimulable(obj); } private void EliminarAutoCreatedCommand() { var osAutoCreated_List = ObjetosSimulables .Where(o => o.Show_On_This_Page && o.AutoCreated) .ToList(); foreach (var obj in osAutoCreated_List) RemoverObjetoSimulable(obj); } private void EliminarClonedCommand() { var osCloned_List = ObjetosSimulables .Where(o => o.Show_On_This_Page && o.Cloned) .ToList(); foreach (var obj in osCloned_List) RemoverObjetoSimulable(obj); } private void AssingPagesCommand() { var assignImagesWindow = new AssignImagesWindow(); var assignImagesViewModel = new AssignImagesViewModel(); assignImagesViewModel.Initialize(this, assignImagesWindow); assignImagesWindow.DataContext = assignImagesViewModel; assignImagesWindow.ShowDialog(); if (assignImagesWindow.DataContext is AssignImagesViewModel dialog && dialog.CloseOK) SaveStateObjetosSimulables(); } private async Task WaitForUIUpdateAsync() { await Task.Yield(); Application.Current.Dispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle); } private async void MultiPageExtractTagsCommand() { var ImagenesSeleccionadas = new ObservableCollection { SelectedImage }; StopSimulation(); var selectPagesWindow = new SelectPages(); var selectPagesViewModel = new SelectPagesViewModel(); selectPagesViewModel.Initialize(this, selectPagesWindow, ref ImagenesSeleccionadas); selectPagesWindow.DataContext = selectPagesViewModel; selectPagesWindow.ShowDialog(); if (selectPagesWindow.DataContext is SelectPagesViewModel dialog && dialog.CloseOK) foreach (var page in ImagenesSeleccionadas) { SelectedImage = page; await WaitForUIUpdateAsync(); // Espera a que la UI se actualice ExtraerTags(); } } private async void MultiPageAnalizeCommand() { var ImagenesSeleccionadas = new ObservableCollection { SelectedImage }; StopSimulation(); var selectPagesWindow = new SelectPages(); var selectPagesViewModel = new SelectPagesViewModel(); selectPagesViewModel.Initialize(this, selectPagesWindow, ref ImagenesSeleccionadas); selectPagesWindow.DataContext = selectPagesViewModel; selectPagesWindow.ShowDialog(); SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen foreach (var page in ImagenesSeleccionadas) { SelectedImage = page; await WaitForUIUpdateAsync(); // Espera a que la UI se actualice AnalizePageCommand(); await WaitForUIUpdateAsync(); // Espera a que la UI se actualice SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen } } private void AnalizePageCommand() { foreach (var obj in ObjetosSimulables) if (obj is osBuscarCoincidencias objBC) if (objBC.Show_On_This_Page) objBC.BuscarCoincidencias(); } /// /// Extrae y formatea las etiquetas de los objetos simulables y las guarda en un archivo Excel. /// private void ExtraerTags() { // Obtiene la ruta del archivo Excel donde se guardarán los datos. var filePath = DatosDeTrabajo.ObtenerPathAllPages(".xlsx"); try { // Crea o abre un libro de Excel. XLWorkbook workbook = File.Exists(filePath) ? new XLWorkbook(filePath) : new XLWorkbook(); var sheetName = "TagsExtracted"; // Obtiene o crea la hoja de trabajo "TagsExtracted". var worksheet = workbook.Worksheets.Contains(sheetName) ? workbook.Worksheet(sheetName) : workbook.Worksheets.Add(sheetName); var lastRowUsed = worksheet.LastRowUsed(); // Determina la fila en la que se empezarán a escribir los datos. int rowOffset = lastRowUsed == null ? 2 : lastRowUsed.RowNumber() + 1; // Determina la columna fija más alta. List columnasOcupadas = new List(); int actualMaxCol = 0; int col = 0; // Filtrar los objetos de tipo osExtraccionTag y crear una nueva lista var osBuscarCoincidencias_List = ObjetosSimulables .OfType() .Where(tag => tag.Show_On_This_Page) .ToList(); var osExtraccionTagBaseGrouped_List = ObjetosSimulables .OfType() .Where(tag => tag.Show_On_This_Page && !tag.Cloned && tag.Id_Search_Templates != null && tag.Id_Search_Templates != "") .ToList(); var osExtraccionTagBaseFix_List = ObjetosSimulables .OfType() .Where(tag => tag.Show_On_This_Page && !tag.Cloned && (tag.Id_Search_Templates == null || tag.Id_Search_Templates == "")) .ToList(); var osExtraccionTagCloned_List = ObjetosSimulables .OfType() .Where(tag => tag.Show_On_This_Page && tag.Cloned) .ToList(); // Columnas Fijas para los Tags no agrupados que no son clonados foreach (var objExtraccionTag in osExtraccionTagBaseFix_List) if ((string.IsNullOrEmpty(objExtraccionTag.Id_Search_Templates)) && !objExtraccionTag.Cloned) { col = objExtraccionTag.Collumn_number; if (col == 0 || columnasOcupadas.Contains(col)) col = ++actualMaxCol; else actualMaxCol = Math.Max(actualMaxCol, col); columnasOcupadas.Add(col); objExtraccionTag.Collumn_number = col; } // Tags Agrupados no Clonados foreach (var objBC in osBuscarCoincidencias_List) foreach (var objExtraccionTag in osExtraccionTagBaseGrouped_List) if (objExtraccionTag.Id_Search_Templates == objBC.Nombre && !objExtraccionTag.Cloned) { col = objExtraccionTag.Collumn_number; if (col == 0 || columnasOcupadas.Contains(col)) col = ++actualMaxCol; else actualMaxCol = Math.Max(actualMaxCol, col); columnasOcupadas.Add(col); objExtraccionTag.Collumn_number = col; } int RowToRender = 0; // Cloned Tag - Asignar las mismas columnas foreach (var oFrom in osExtraccionTagBaseGrouped_List) foreach (var oCloned in osExtraccionTagCloned_List) { if (oCloned.Cloned_from == oFrom.Id) oCloned.Collumn_number = oFrom.Collumn_number; RowToRender = Math.Max(RowToRender, oCloned.Copy_Number); } // Render Rows for (int row = 0; row < RowToRender; row++) { // Render Fix tags foreach (var TagFixs in osExtraccionTagBaseFix_List) { col = TagFixs.Collumn_number; if (worksheet.Cell(1, col).IsEmpty()) worksheet.Cell(1, col).Value = TagFixs.Collumn_name; TagFixs.CaptureImageAreaAndDoOCR(); worksheet.Cell(row + rowOffset, col).Value = TagFixs.Tag_extract; } // Render Cloned tags foreach (var TagCloned in osExtraccionTagCloned_List) { if (TagCloned.Copy_Number == row) // Estamos en la fila correcta { col = TagCloned.Collumn_number; if (worksheet.Cell(1, col).IsEmpty()) worksheet.Cell(1, col).Value = TagCloned.Collumn_name; TagCloned.CaptureImageAreaAndDoOCR(); worksheet.Cell(row + rowOffset, col).Value = TagCloned.Tag_extract; } } } // Formatear los títulos en la fila 1 var titleRow = worksheet.Row(1); titleRow.Style.Font.Bold = true; titleRow.Style.Fill.BackgroundColor = XLColor.LightGray; titleRow.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; // Auto dimensionado de las columnas utilizadas worksheet.Columns().AdjustToContents(); // Guarda el libro de Excel. workbook.SaveAs(filePath); } catch (IOException ex) { // Muestra un diálogo de error si ocurre una excepción de IO. var dialog = new TaskDialog { WindowTitle = "IOException", MainInstruction = "Error al acceder al archivo", Content = $"El proceso no puede acceder al archivo '{filePath}' porque está siendo utilizado por otro proceso.", ExpandedInformation = ex.ToString(), MainIcon = TaskDialogIcon.Error, ButtonStyle = TaskDialogButtonStyle.Standard }; dialog.Buttons.Add(new TaskDialogButton(ButtonType.Ok)); dialog.ShowDialog(); } } private void InitializeTipoSimulableList() { var baseType = typeof(osBase); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract && typeof(IosBase).IsAssignableFrom(type)); foreach (var type in types) { var methodInfo = type.GetMethod("NombreClase", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); string nombre = methodInfo != null ? methodInfo.Invoke(null, null)?.ToString() : "Nombre no encontrado"; ListaOsBase.Add(new TipoSimulable { Nombre = nombre, Tipo = type }); } } private void StartSimulation() { IsSimulationRunning = true; foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.UpdateGeometryStart(); simulationManager.Debug_DrawInitialBodies(); TiempoDesdeStartSimulacion = 0; Debug_SimulacionCreado = true; _timerSimulacion.Start(); } private void StopSimulation() { IsSimulationRunning = false; foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.SimulationStop(); if (Debug_SimulacionCreado) { simulationManager.Debug_ClearSimulationShapes(); Debug_SimulacionCreado = false; } _timerSimulacion.Stop(); } private void OnTickSimulacion(object sender, EventArgs e) { // Detener el cronómetro y obtener el tiempo transcurrido en milisegundos var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimModel_last; stopwatch_SimModel_last = stopwatch_Sim.Elapsed.TotalMilliseconds; // Eliminar el diseño de Debug luego de 2 segundos if (TiempoDesdeStartSimulacion > 12000) simulationManager.Debug_ClearSimulationShapes(); else TiempoDesdeStartSimulacion += (float)elapsedMilliseconds; foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.UpdateGeometryStep(); simulationManager.Step(); var objetosSimulablesCopy = new List(ObjetosSimulables); foreach (var objetoSimulable in objetosSimulablesCopy) { if (!objetoSimulable.RemoverDesdeSimulacion) objetoSimulable.UpdateControl((int)elapsedMilliseconds); else RemoverObjetoSimulable(objetoSimulable); } } private void ConnectPLC() { PLCViewModel.Connect(); } private void DisconnectPLC() { PLCViewModel.Disconnect(); IsConnected = false; foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.SetPLC(null); } private void OnRefreshEvent(object sender, EventArgs e) { if (PLCViewModel.IsConnected) { if (!isConnected) { IsConnected = true; foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.SetPLC(PLCViewModel.PLCInterface); } // Detener el cronómetro y obtener el tiempo transcurrido en milisegundos var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimPLC_last; stopwatch_SimPLC_last = stopwatch_Sim.Elapsed.TotalMilliseconds; // Reiniciar el cronómetro para la próxima medición foreach (var objetoSimulable in ObjetosSimulables) objetoSimulable.UpdatePLC(PLCViewModel.PLCInterface, (int)elapsedMilliseconds); } } private void OpenWorkDirectory() { var dialog = new VistaFolderBrowserDialog(); if (dialog.ShowDialog() == true) // Mostrar el diálogo y comprobar si el resultado es positivo { directorioTrabajo = dialog.SelectedPath; // Actualizar la propiedad que también actualiza el estado persistente } } // // Lista de osBase // public void Save() { SaveStateObjetosSimulables(); } public void SaveStateObjetosSimulables() { if (SelectedImage != null) { StopSimulation(); DisconnectPLC(); ObservableCollection _objetosSimulables = new ObservableCollection(); ObservableCollection _objetosSimulablesAllPages = new ObservableCollection(); foreach (var obj in ObjetosSimulables) { // Guardar referencias temporales obj.SalvarDatosNoSerializables(); if (!obj.Enable_On_All_Pages) _objetosSimulables.Add(obj); else _objetosSimulablesAllPages.Add(obj); } // Salvar los objetos de la pagina actual // Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter y PLC_ConnectionData var dataToSerialize = new SimulationData { ObjetosSimulables = _objetosSimulables, UnitConverter = PixelToMeter.Instance.calc, PLC_ConnectionData = PLCViewModel }; // Ruta del archivo a ser guardado var path = DatosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json"); if (path != null) SerializarYSalvar(dataToSerialize, path); // Salvar los objetos de todas las paginas // Ruta del archivo a ser guardado path = DatosDeTrabajo.ObtenerPathAllPages(".json"); if (path != null) SerializarYSalvar(_objetosSimulablesAllPages, path); // Restaurar las propiedades originales de los objetos foreach (var obj in ObjetosSimulables) obj.RestaurarDatosNoSerializables(); } } private void SerializarYSalvar(object listaObjetos, string path) { // Verificar si el archivo ya existe y crear un respaldo if (File.Exists(path)) { var backupPath = Path.ChangeExtension(path, ".bak"); File.Copy(path, backupPath, true); // Copia el archivo existente a un nuevo archivo .bak, sobrescribiendo si es necesario } var settings = new JsonSerializerSettings { Formatting = Formatting.Indented, // PreserveReferencesHandling = PreserveReferencesHandling.Objects, NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto }; // Serializar var serializedData = JsonConvert.SerializeObject(listaObjetos, settings); File.WriteAllText(path, serializedData); // Escribir el nuevo archivo JSON } public void LoadStateObjetosSimulables() { try { StopSimulation(); DisconnectPLC(); ObjetosSimulables.Clear(); simulationManager.Clear(); if (SelectedImage != null) { var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, ObjectCreationHandling = ObjectCreationHandling.Replace, // PreserveReferencesHandling = PreserveReferencesHandling.Objects, ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor }; string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json"); if (File.Exists(jsonPath)) { string jsonString = File.ReadAllText(jsonPath); var simulationData = JsonConvert.DeserializeObject(jsonString, settings); if (simulationData != null) { if (simulationData.ObjetosSimulables is not null) ObjetosSimulables = simulationData.ObjetosSimulables; if (simulationData.PLC_ConnectionData is not null) PLCViewModel = simulationData.PLC_ConnectionData; else PLCViewModel = new PLCViewModel(); PixelToMeter.Instance.calc = simulationData.UnitConverter; // Re-register to the events PLCViewModel.RefreshEvent += OnRefreshEvent; } } jsonPath = DatosDeTrabajo.ObtenerPathAllPages(".json"); if (File.Exists(jsonPath)) { string jsonString = File.ReadAllText(jsonPath); ObservableCollection _objetosSimulablesAllPages = new ObservableCollection(); _objetosSimulablesAllPages = JsonConvert.DeserializeObject>(jsonString, settings); if (_objetosSimulablesAllPages != null) foreach (var obj in _objetosSimulablesAllPages) ObjetosSimulables.Add(obj); } // Recorrer la colección de objetos simulables foreach (var objetoSimulable in ObjetosSimulables) if (objetoSimulable != null) CrearUserControlDesdeObjetoSimulable(objetoSimulable); } } catch { /* Consider logging the error or handling it appropriately */ } } // Se cargan los datos de cada UserControl en el StackPanel public void CargarPropiedadesosDatos(osBase selectedObject, PropertyGrid PanelEdicion, ResourceDictionary Resources) { UserControlFactory.CargarPropiedadesosDatos(selectedObject, PanelEdicion); } private RelayCommand saveCommand; public ICommand SaveCommand => saveCommand ??= new RelayCommand(Save); private void Save(object commandParameter) { } private RelayCommand exitCommand; public ICommand ExitCommand => exitCommand ??= new RelayCommand(Exit); private void Exit() { Save(); Application.Current.Shutdown(); } } public class SimulationData { public ObservableCollection? ObjetosSimulables { get; set; } public UnitConverter? UnitConverter { get; set; } public PLCViewModel? PLC_ConnectionData { get; set; } } public class TipoSimulable { public string? Nombre { get; set; } public Type? Tipo { get; set; } } public class TickSimulacionEventArgs : EventArgs { // Aquí puedes agregar propiedades o campos para pasar información adicional // en el evento TickSimulacion } }