diff --git a/CtrEditor.csproj b/CtrEditor.csproj
index 81cb2ab..5fd72e8 100644
--- a/CtrEditor.csproj
+++ b/CtrEditor.csproj
@@ -10,11 +10,11 @@
- False
+ True
- False
+ True
diff --git a/DatosDeTrabajo.cs b/DatosDeTrabajo.cs
index 277aced..385d8c3 100644
--- a/DatosDeTrabajo.cs
+++ b/DatosDeTrabajo.cs
@@ -30,14 +30,11 @@ namespace CtrEditor
public string? ObtenerPathAllPages(string extension)
{
- string folderPath = EstadoPersistente.Instance.directorio; // Usar directamente desde el Singleton
-
- if (Directory.Exists(folderPath))
- return Path.ChangeExtension(folderPath + "\\allpages", extension);
- else return null;
+ if (!string.IsNullOrEmpty(EstadoPersistente.Instance.directorio))
+ return Path.Combine(EstadoPersistente.Instance.directorio, "AllPages" + extension);
+ return null;
}
-
public void CargarImagenes()
{
Imagenes.Clear();
diff --git a/FuncionesBase/TagPattern.cs b/FuncionesBase/TagPattern.cs
index 649defa..893e648 100644
--- a/FuncionesBase/TagPattern.cs
+++ b/FuncionesBase/TagPattern.cs
@@ -16,6 +16,7 @@ namespace CtrEditor.FuncionesBase
{ "Siemens IO Input", "Format: Exxxxx.y (x: 0-65535, y: 0-7)" },
{ "Siemens IO Output", "Format: Axxxxx.y (x: 0-65535, y: 0-7)" },
{ "LETRASNUMEROS", "Format: ABC...123... (1-10 letters + numbers)" },
+ { "LETRASNUMEROSESPACIOS", "Format: ABC...123... (letters, numbers and spaces allowed)" },
{ "Numero", "Numeric value" }
};
@@ -35,6 +36,7 @@ namespace CtrEditor.FuncionesBase
"Siemens IO Input" => ApplySiemensPattern(text, "E"),
"Siemens IO Output" => ApplySiemensPattern(text, "A"),
"LETRASNUMEROS" => ApplyLetrasNumerosPattern(text),
+ "LETRASNUMEROSESPACIOS" => ApplyLetrasNumerosEspaciosPattern(text),
"Numero" => ApplyNumberPattern(text),
_ => text
};
@@ -77,6 +79,15 @@ namespace CtrEditor.FuncionesBase
return $"{letters.ToUpper()}{numbers}";
}
+ private static string ApplyLetrasNumerosEspaciosPattern(string text)
+ {
+ // Keep only letters, numbers and spaces
+ var cleanedText = new string(text.Where(c => char.IsLetterOrDigit(c) || char.IsWhiteSpace(c)).ToArray());
+
+ // Convert to uppercase
+ return cleanedText.ToUpper();
+ }
+
private static string ApplyNumberPattern(string text)
{
var match = Regex.Match(text, @"-?\d+\.?\d*");
diff --git a/MainViewModel.cs b/MainViewModel.cs
index 84e0b19..f9b6018 100644
--- a/MainViewModel.cs
+++ b/MainViewModel.cs
@@ -21,13 +21,14 @@ using System.Windows.Data;
using CommunityToolkit.Mvvm.Input;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
-
+using CtrEditor.Serialization; // Add this line
namespace CtrEditor
{
public partial class MainViewModel : ObservableObject
{
+ private readonly StateSerializer _stateSerializer;
public Stopwatch stopwatch_Sim;
private double stopwatch_SimPLC_last;
@@ -367,6 +368,7 @@ namespace CtrEditor
OpenRecentDirectoryCommand = new RelayCommand(OpenRecentDirectory);
_stateManager = new StateManager(EstadoPersistente.Instance.directorio, this);
+ _stateSerializer = new StateSerializer(this, datosDeTrabajo, simulationManager);
}
private void OsListFilter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@@ -425,7 +427,7 @@ namespace CtrEditor
}
// Crear UserControl desde osBase : Nuevo o desde Deserealizacion
- private bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto)
+ public bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto)
{
Type tipoObjeto = osObjeto.GetType();
@@ -513,25 +515,9 @@ namespace CtrEditor
}
- public void EliminarObjetoSeleccionado()
- {
- if (SelectedItemOsList is osBase objEliminar)
- {
- var result = MessageBox.Show($"¿Está seguro que desea eliminar el objeto '{objEliminar.Nombre}'?",
- "Confirmar eliminación",
- MessageBoxButton.YesNo,
- MessageBoxImage.Question);
-
- if (result == MessageBoxResult.Yes)
- {
- RemoverObjetoSimulable(objEliminar);
- }
- }
- }
-
private void EliminarUserControl()
{
- EliminarObjetoSeleccionado();
+ _objectManager.EliminarObjetosSeleccionados();
}
@@ -661,7 +647,7 @@ namespace CtrEditor
simulationManager.Start();
}
- private void StopSimulation()
+ public void StopSimulation()
{
IsSimulationRunning = false;
@@ -717,7 +703,7 @@ namespace CtrEditor
objetoSimulable.SetPLC(PLCViewModel);
}
- private void DisconnectPLC()
+ public void DisconnectPLC()
{
PLCViewModel.Disconnect();
_timerPLCUpdate.Stop();
@@ -822,138 +808,17 @@ namespace CtrEditor
{
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();
-
+ _stateSerializer.SaveState(SelectedImage);
HasUnsavedChanges = false;
}
}
- 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
+ if (SelectedImage != null)
{
- 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;
-
- }
- }
-
- 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)
- {
- objetoSimulable.CheckData();
- CrearUserControlDesdeObjetoSimulable(objetoSimulable);
- }
- }
+ _stateSerializer.LoadState(SelectedImage);
}
- catch { /* Consider logging the error or handling it appropriately */ }
}
// Se cargan los datos de cada UserControl en el StackPanel
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 8f12648..14f4428 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -256,8 +256,12 @@
ResizeDirection="Rows" VerticalAlignment="Center" />
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 157d689..911eafe 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -287,17 +287,20 @@ namespace CtrEditor
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
- // Forzar el foco al canvas si no lo tiene
- if (!ImagenEnTrabajoCanvas.IsFocused)
+ // Only force canvas focus if PanelEdicion doesn't have focus
+ if (!PanelEdicion.IsKeyboardFocusWithin)
{
- ImagenEnTrabajoCanvas.Focus();
+ if (!ImagenEnTrabajoCanvas.IsFocused)
+ {
+ ImagenEnTrabajoCanvas.Focus();
+ }
}
if (DataContext is MainViewModel viewModel)
{
if (e.Key == Key.Delete)
{
- viewModel.EliminarObjetoSeleccionado();
+ _objectManager.EliminarObjetosSeleccionados();
e.Handled = true;
}
else if (e.Key == Key.Escape)
@@ -491,13 +494,18 @@ namespace CtrEditor
private void Canvas_KeyDown(object sender, KeyEventArgs e)
{
- HandleKeyDown(e);
+ // Only handle if PanelEdicion doesn't have focus
+ if (!PanelEdicion.IsKeyboardFocusWithin)
+ {
+ HandleKeyDown(e);
+ }
}
private void ScrollViewer_PreviewKeyDown(object sender, KeyEventArgs e)
{
- // Prevenir que el ScrollViewer maneje las teclas de flecha
- if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
+ // Only handle if PanelEdicion doesn't have focus
+ if (!PanelEdicion.IsKeyboardFocusWithin &&
+ (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down))
{
HandleKeyDown(e);
e.Handled = true;
@@ -510,7 +518,7 @@ namespace CtrEditor
{
if (e.Key == Key.Delete)
{
- viewModel.EliminarObjetoSeleccionado();
+ _objectManager.EliminarObjetosSeleccionados(); // Cambiar aquí
e.Handled = true;
}
else if (e.Key == Key.Escape)
diff --git a/ObjectManipulationManager.cs b/ObjectManipulationManager.cs
index 3360ef3..32620e8 100644
--- a/ObjectManipulationManager.cs
+++ b/ObjectManipulationManager.cs
@@ -75,9 +75,25 @@ namespace CtrEditor
_canvas = canvas;
}
+ private void PurgeDeletedObjects()
+ {
+ var deletedObjects = _selectedObjects.Where(obj =>
+ obj.VisualRepresentation == null ||
+ !_canvas.Children.Contains(obj.VisualRepresentation)).ToList();
+
+ foreach (var obj in deletedObjects)
+ {
+ DeselectObject(obj);
+ }
+ }
+
public ObservableCollection SelectedObjects
{
- get => _selectedObjects;
+ get
+ {
+ PurgeDeletedObjects();
+ return _selectedObjects;
+ }
private set
{
_selectedObjects = value;
@@ -87,6 +103,7 @@ namespace CtrEditor
public void UpdateSelectionVisuals()
{
+ PurgeDeletedObjects();
// Asegurarse de que el canvas haya actualizado su layout
_canvas.UpdateLayout();
@@ -308,6 +325,7 @@ namespace CtrEditor
private void HandleObjectSelection(UserControl userControl, osBase datos)
{
+ PurgeDeletedObjects();
var viewModel = _mainWindow.DataContext as MainViewModel;
if (viewModel == null) return;
@@ -545,6 +563,7 @@ namespace CtrEditor
private void HandleDrag(Point currentPosition)
{
+ PurgeDeletedObjects();
var dx = currentPosition.X - _startPointUserControl.X;
var dy = currentPosition.Y - _startPointUserControl.Y;
@@ -695,6 +714,7 @@ namespace CtrEditor
private void HandleResize(Point currentPosition, HandleMode mode)
{
+ PurgeDeletedObjects();
RemoveAllSelectionHighlights(); // Remover antes de redimensionar
foreach (var selectedObject in _selectedObjects)
@@ -718,6 +738,7 @@ namespace CtrEditor
private void HandleRotation(Point currentPosition)
{
+ PurgeDeletedObjects();
RemoveAllSelectionHighlights(); // Remover antes de rotar
// Calcular el ángulo respecto al centro del bounding box que contiene todos los objetos seleccionados
@@ -744,6 +765,7 @@ namespace CtrEditor
public void AlignObjects(AlignmentType alignmentType)
{
+ PurgeDeletedObjects();
if (_selectedObjects.Count <= 1) return;
var alignment = new ObjectAlignment(_selectedObjects, _selectedObjects.FirstOrDefault());
@@ -794,5 +816,32 @@ namespace CtrEditor
// Update the selection visuals after alignment
UpdateSelectionVisuals();
}
+
+ public void EliminarObjetosSeleccionados()
+ {
+ if (_selectedObjects.Count == 0) return;
+
+ var viewModel = _mainWindow.DataContext as MainViewModel;
+ if (viewModel == null) return;
+
+ // Crear una copia de la lista para evitar modificaciones durante la iteración
+ var objectsToRemove = _selectedObjects.ToList();
+
+ foreach (var obj in objectsToRemove)
+ {
+ viewModel.RemoverObjetoSimulable(obj);
+ }
+
+ // Limpiar la selección y actualizar la interfaz
+ ClearSelection();
+ RemoveResizeRectangles();
+ RemoveAllSelectionHighlights();
+
+ // Actualizar el estado de cambios sin guardar
+ if (viewModel != null)
+ {
+ viewModel.HasUnsavedChanges = true;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Serialization/StateSerializer.cs b/Serialization/StateSerializer.cs
new file mode 100644
index 0000000..ad83bc3
--- /dev/null
+++ b/Serialization/StateSerializer.cs
@@ -0,0 +1,162 @@
+using CtrEditor.ObjetosSim;
+using LibS7Adv;
+using Newtonsoft.Json;
+using System.Collections.ObjectModel;
+using System.Windows;
+using CtrEditor.Simulacion;
+using System.IO;
+
+namespace CtrEditor.Serialization
+{
+ public class StateSerializer
+ {
+ private readonly DatosDeTrabajo _datosDeTrabajo;
+ private readonly MainViewModel _mainViewModel;
+ private readonly SimulationManagerFP _simulationManager;
+
+ public StateSerializer(MainViewModel mainViewModel, DatosDeTrabajo datosDeTrabajo, SimulationManagerFP simulationManager)
+ {
+ _mainViewModel = mainViewModel;
+ _datosDeTrabajo = datosDeTrabajo;
+ _simulationManager = simulationManager;
+ }
+
+ public void SaveState(string selectedImage)
+ {
+ if (selectedImage != null)
+ {
+ _mainViewModel.StopSimulation();
+ _mainViewModel.DisconnectPLC();
+
+ var objetosSimulables = new ObservableCollection();
+ var objetosSimulablesAllPages = new ObservableCollection();
+
+ foreach (var obj in _mainViewModel.ObjetosSimulables)
+ {
+ obj.SalvarDatosNoSerializables();
+ if (!obj.Enable_On_All_Pages)
+ objetosSimulables.Add(obj);
+ else
+ objetosSimulablesAllPages.Add(obj);
+ }
+
+ // Save current page objects
+ var dataToSerialize = new SimulationData
+ {
+ ObjetosSimulables = objetosSimulables,
+ UnitConverter = PixelToMeter.Instance.calc,
+ PLC_ConnectionData = _mainViewModel.PLCViewModel
+ };
+
+ var path = _datosDeTrabajo.ObtenerPathImagenConExtension(selectedImage, ".json");
+ if (path != null)
+ SerializeAndSave(dataToSerialize, path);
+
+ // Save all pages objects
+ path = _datosDeTrabajo.ObtenerPathAllPages(".json");
+ if (path != null)
+ SerializeAndSave(objetosSimulablesAllPages, path);
+
+ // Restore original properties
+ foreach (var obj in _mainViewModel.ObjetosSimulables)
+ obj.RestaurarDatosNoSerializables();
+ }
+ }
+
+ public void LoadState(string selectedImage)
+ {
+ try
+ {
+ _mainViewModel.StopSimulation();
+ _mainViewModel.DisconnectPLC();
+ _mainViewModel.ObjetosSimulables.Clear();
+ _simulationManager.Clear();
+
+ if (selectedImage != null)
+ {
+ var settings = GetJsonSerializerSettings();
+ LoadCurrentPageState(selectedImage, settings);
+ LoadAllPagesState(settings);
+
+ // Create UserControls for all loaded objects
+ foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
+ {
+ if (objetoSimulable != null)
+ {
+ objetoSimulable.CheckData();
+ _mainViewModel.CrearUserControlDesdeObjetoSimulable(objetoSimulable);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Error loading state: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ private void LoadCurrentPageState(string selectedImage, JsonSerializerSettings settings)
+ {
+ 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)
+ _mainViewModel.ObjetosSimulables = simulationData.ObjetosSimulables;
+
+ if (simulationData.PLC_ConnectionData is not null)
+ _mainViewModel.PLCViewModel = simulationData.PLC_ConnectionData;
+ else
+ _mainViewModel.PLCViewModel = new PLCViewModel();
+
+ PixelToMeter.Instance.calc = simulationData.UnitConverter;
+ }
+ }
+ }
+
+ private void LoadAllPagesState(JsonSerializerSettings settings)
+ {
+ string jsonPath = _datosDeTrabajo.ObtenerPathAllPages(".json");
+ if (File.Exists(jsonPath))
+ {
+ string jsonString = File.ReadAllText(jsonPath);
+ var objetosSimulablesAllPages = JsonConvert.DeserializeObject>(jsonString, settings);
+ if (objetosSimulablesAllPages != null)
+ {
+ foreach (var obj in objetosSimulablesAllPages)
+ _mainViewModel.ObjetosSimulables.Add(obj);
+ }
+ }
+ }
+
+ private void SerializeAndSave(object objectToSerialize, string path)
+ {
+ // Create backup if file exists
+ if (File.Exists(path))
+ {
+ var backupPath = Path.ChangeExtension(path, ".bak");
+ File.Copy(path, backupPath, true);
+ }
+
+ var settings = GetJsonSerializerSettings();
+ var serializedData = JsonConvert.SerializeObject(objectToSerialize, settings);
+ File.WriteAllText(path, serializedData);
+ }
+
+ private JsonSerializerSettings GetJsonSerializerSettings()
+ {
+ return new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Ignore,
+ TypeNameHandling = TypeNameHandling.Auto,
+ ObjectCreationHandling = ObjectCreationHandling.Replace,
+ ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
+ };
+ }
+ }
+}
+