Creada las opciones de datos locales para las posiciones de los objetos globales

This commit is contained in:
Miguel 2025-03-26 21:12:04 +01:00
parent 211c518be6
commit 98c5f2e6ff
5 changed files with 451 additions and 12 deletions

View File

@ -1011,11 +1011,15 @@ namespace CtrEditor
_objectManager.UpdateSelectionVisuals();
}
}
public class SimulationData
{
public ObservableCollection<osBase>? ObjetosSimulables { get; set; }
public UnitConverter? UnitConverter { get; set; }
public PLCViewModel? PLC_ConnectionData { get; set; }
// Nueva propiedad para almacenar los datos locales de objetos globales
public ObservableCollection<DatosLocales>? DatosLocalesObjetos { get; set; }
}
public class TipoSimulable

View File

@ -1,5 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.FuncionesBase;
using CtrEditor.Serialization;
using CtrEditor.Simulacion;
using LibS7Adv;
using nkast.Aether.Physics2D.Common;
@ -449,10 +450,151 @@ namespace CtrEditor.ObjetosSim
[property: Category("Layout:")]
private bool enable_On_All_Pages;
partial void OnEnable_On_All_PagesChanged(bool value)
{
// Si se está desactivando el modo global
if (!value)
{
// Limpiar los datos locales
_datosLocales = null;
_snapshotGlobal = null;
// Desactivar datos locales
Enable_Local_Data = false;
Show_On_This_Page = true;
}
}
// Local Data for Global Objects
[NotifyPropertyChangedFor(nameof(Show_On_This_Page))]
[ObservableProperty]
[property: Description("Enable local data of this global Object on all pages.")]
[property: Category("Layout:")]
private bool enable_Local_Data_for_All;
partial void OnEnable_Local_Data_for_AllChanged(bool value)
{
if (value)
{
// Activar datos locales
Enable_Local_Data = true;
}
}
// Local Data for Global Objects
[NotifyPropertyChangedFor(nameof(Show_On_This_Page))]
[ObservableProperty]
[property: Description("Enable local data of this global Object on this page.")]
[property: Category("Layout:")]
[property: JsonIgnore]
private bool enable_Local_Data;
// Añadir estas propiedades y métodos a la clase osBase
[JsonIgnore]
private DatosLocales _snapshotGlobal;
[JsonIgnore]
private DatosLocales _datosLocales;
/// <summary>
/// Crea un snapshot de los datos globales actuales
/// </summary>
public void CrearSnapshotGlobal()
{
if (Enable_On_All_Pages) // No verificamos Enable_Local_Data aquí
{
_snapshotGlobal = new DatosLocales(Id);
_snapshotGlobal.CopiarDesdeObjeto(this);
}
}
/// <summary>
/// Restaura los datos globales desde el snapshot
/// </summary>
public void RestaurarDesdeSnapshotGlobal()
{
if (Enable_On_All_Pages && Enable_Local_Data && _snapshotGlobal != null)
{
// Guarda los datos locales actuales antes de restaurar
if (_datosLocales == null)
{
_datosLocales = new DatosLocales(Id);
}
_datosLocales.CopiarDesdeObjeto(this);
// Restaura desde el snapshot
_snapshotGlobal.AplicarAObjeto(this);
}
}
/// <summary>
/// Restaura los datos locales después de guardar
/// </summary>
public void RestaurarDatosLocales()
{
if (Enable_On_All_Pages && Enable_Local_Data && _datosLocales != null)
{
_datosLocales.AplicarAObjeto(this);
}
}
/// <summary>
/// Obtiene los datos locales del objeto
/// </summary>
public DatosLocales ObtenerDatosLocales()
{
if (!Enable_On_All_Pages)
return null;
DatosLocales datos = new DatosLocales(Id);
datos.CopiarDesdeObjeto(this);
return datos;
}
/// <summary>
/// Aplica datos locales al objeto
/// </summary>
public void AplicarDatosLocales(DatosLocales datos)
{
if (Enable_On_All_Pages && datos != null && datos.Id_GlobalObject.Value == Id.Value)
{
Enable_Local_Data = true; // Activar datos locales si se encuentran
datos.AplicarAObjeto(this);
// Actualiza la visualización
ActualizarLeftTop();
OnAnchoChanged(Ancho);
OnAltoChanged(Alto);
}
}
partial void OnEnable_Local_DataChanged(bool value)
{
// Si se está desactivando los datos locales y teníamos un snapshot
if (!value && _snapshotGlobal != null && Enable_On_All_Pages)
{
// Restaurar los valores globales
_snapshotGlobal.AplicarAObjeto(this);
// Limpiar los datos locales
_datosLocales = null;
_snapshotGlobal = null;
// Actualizar la visualización
ActualizarLeftTop();
OnAnchoChanged(Ancho);
OnAltoChanged(Alto);
}
// Si se está activando, crear el snapshot
else if (value && Enable_On_All_Pages)
{
CrearSnapshotGlobal();
}
}
[ObservableProperty]

View File

@ -0,0 +1,91 @@
using CtrEditor.ObjetosSim;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace CtrEditor.Serialization
{
/// <summary>
/// Almacena datos locales para un objeto global
/// </summary>
public class DatosLocales
{
/// <summary>
/// ID del objeto global al que pertenecen estos datos locales
/// </summary>
public UniqueId Id_GlobalObject { get; set; }
/// <summary>
/// Posición vertical local
/// </summary>
public float? Top { get; set; }
/// <summary>
/// Posición horizontal local
/// </summary>
public float? Left { get; set; }
/// <summary>
/// Ancho local
/// </summary>
public float? Ancho { get; set; }
/// <summary>
/// Alto local
/// </summary>
public float? Alto { get; set; }
/// <summary>
/// Diccionario para almacenar propiedades dinámicas adicionales
/// </summary>
public Dictionary<string, object> PropiedadesAdicionales { get; set; }
/// <summary>
/// Constructor por defecto necesario para deserialización
/// </summary>
public DatosLocales()
{
PropiedadesAdicionales = new Dictionary<string, object>();
}
/// <summary>
/// Constructor con ID del objeto global
/// </summary>
public DatosLocales(UniqueId idGlobalObject)
{
Id_GlobalObject = idGlobalObject;
PropiedadesAdicionales = new Dictionary<string, object>();
}
/// <summary>
/// Copia los datos relevantes desde un objeto global
/// </summary>
public void CopiarDesdeObjeto(osBase objeto)
{
if (objeto == null) return;
Id_GlobalObject = objeto.Id;
Top = objeto.Top;
Left = objeto.Left;
Ancho = objeto.Ancho;
Alto = objeto.Alto;
// Aquí puedes añadir más propiedades si es necesario
}
/// <summary>
/// Aplica los datos locales al objeto global
/// </summary>
public void AplicarAObjeto(osBase objeto)
{
if (objeto == null || objeto.Id.Value != Id_GlobalObject.Value) return;
if (Left.HasValue) objeto.Left = Left.Value;
if (Top.HasValue) objeto.Top = Top.Value;
if (Ancho.HasValue) objeto.Ancho = Ancho.Value;
if (Alto.HasValue) objeto.Alto = Alto.Value;
// Aquí puedes aplicar más propiedades si es necesario
}
}
}

View File

@ -0,0 +1,128 @@
using CtrEditor.ObjetosSim;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
namespace CtrEditor.Serialization
{
/// <summary>
/// Clase para gestionar qué propiedades deben ser locales en objetos globales
/// </summary>
public static class PropiedadesLocalesManager
{
// Definición de propiedades por defecto que se guardan localmente para todos los objetos
private static readonly List<string> PropiedadesPorDefecto = new List<string>
{
"Left", "Top", "Ancho", "Alto"
};
// Diccionario que contiene conjuntos de propiedades locales por tipo de objeto
private static readonly Dictionary<Type, List<string>> PropiedadesPorTipo = new Dictionary<Type, List<string>>();
/// <summary>
/// Registra un conjunto de propiedades locales para un tipo específico de objeto
/// </summary>
/// <typeparam name="T">Tipo de objeto (debe heredar de osBase)</typeparam>
/// <param name="propiedades">Lista de nombres de propiedades a registrar como locales</param>
public static void RegistrarPropiedadesParaTipo<T>(List<string> propiedades) where T : osBase
{
PropiedadesPorTipo[typeof(T)] = propiedades;
}
/// <summary>
/// Obtiene la lista de propiedades que deben ser locales para un objeto concreto
/// </summary>
/// <param name="objeto">Objeto del que obtener las propiedades locales</param>
/// <returns>Lista de nombres de propiedades</returns>
public static List<string> ObtenerPropiedadesLocales(osBase objeto)
{
var resultado = new List<string>(PropiedadesPorDefecto);
if (objeto != null && PropiedadesPorTipo.TryGetValue(objeto.GetType(), out var propiedadesExtra))
{
foreach (var prop in propiedadesExtra)
{
if (!resultado.Contains(prop))
resultado.Add(prop);
}
}
return resultado;
}
/// <summary>
/// Crea un objeto dinámico que permite acceder a las propiedades locales de un objeto
/// </summary>
/// <param name="objeto">Objeto del que crear una vista dinámica</param>
/// <returns>Objeto dinámico con propiedades locales</returns>
public static dynamic CrearAccesoDinamico(osBase objeto)
{
return new PropiedadesLocalesDinamicas(objeto);
}
/// <summary>
/// Clase interna que implementa un acceso dinámico a propiedades
/// </summary>
private class PropiedadesLocalesDinamicas : DynamicObject
{
private readonly osBase _objeto;
private readonly List<string> _propiedadesLocales;
public PropiedadesLocalesDinamicas(osBase objeto)
{
_objeto = objeto;
_propiedadesLocales = ObtenerPropiedadesLocales(objeto);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var nombrePropiedad = binder.Name;
if (_propiedadesLocales.Contains(nombrePropiedad))
{
var propInfo = _objeto.GetType().GetProperty(nombrePropiedad);
if (propInfo != null && propInfo.CanRead)
{
result = propInfo.GetValue(_objeto);
return true;
}
}
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var nombrePropiedad = binder.Name;
if (_propiedadesLocales.Contains(nombrePropiedad))
{
var propInfo = _objeto.GetType().GetProperty(nombrePropiedad);
if (propInfo != null && propInfo.CanWrite)
{
try
{
var valorConvertido = Convert.ChangeType(value, propInfo.PropertyType);
propInfo.SetValue(_objeto, valorConvertido);
return true;
}
catch (Exception)
{
// Silenciar errores de conversión
}
}
}
return false;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _propiedadesLocales;
}
}
}
}

View File

@ -5,6 +5,7 @@ using System.Collections.ObjectModel;
using System.Windows;
using CtrEditor.Simulacion;
using System.IO;
using System.Linq;
namespace CtrEditor.Serialization
{
@ -30,36 +31,68 @@ namespace CtrEditor.Serialization
var objetosSimulables = new ObservableCollection<osBase>();
var objetosSimulablesAllPages = new ObservableCollection<osBase>();
var datosLocalesObjetos = new ObservableCollection<DatosLocales>();
// Paso 1: Preparar objetos globales y locales
foreach (var obj in _mainViewModel.ObjetosSimulables)
{
// Para objetos globales con datos locales
if (obj.Enable_On_All_Pages && obj.Enable_Local_Data)
{
// Guarda los datos locales independientemente de Show_On_This_Page
var datosLocales = obj.ObtenerDatosLocales();
if (datosLocales != null)
{
datosLocalesObjetos.Add(datosLocales);
}
// Restaura datos globales para guardar
obj.RestaurarDesdeSnapshotGlobal();
}
// Prepara para serialización
obj.SalvarDatosNoSerializables();
// Separa objetos globales y locales
if (!obj.Enable_On_All_Pages)
{
objetosSimulables.Add(obj);
}
else
{
objetosSimulablesAllPages.Add(obj);
}
}
// Save current page objects
// Paso 2: Guardar datos de la página actual
var dataToSerialize = new SimulationData
{
ObjetosSimulables = objetosSimulables,
ObjetosSimulables = objetosSimulables.Count > 0 ? objetosSimulables : null,
UnitConverter = PixelToMeter.Instance.calc,
PLC_ConnectionData = _mainViewModel.PLCViewModel
PLC_ConnectionData = _mainViewModel.PLCViewModel,
DatosLocalesObjetos = datosLocalesObjetos.Count > 0 ? datosLocalesObjetos : null
};
var path = _datosDeTrabajo.ObtenerPathImagenConExtension(selectedImage, ".json");
if (path != null)
SerializeAndSave(dataToSerialize, path);
// Save all pages objects
// Paso 3: Guardar objetos globales
path = _datosDeTrabajo.ObtenerPathAllPages(".json");
if (path != null)
SerializeAndSave(objetosSimulablesAllPages, path);
// Restore original properties
// Paso 4: Restaurar estado para seguir trabajando
foreach (var obj in _mainViewModel.ObjetosSimulables)
{
obj.RestaurarDatosNoSerializables();
// Para objetos globales, restaura los datos locales
if (obj.Enable_On_All_Pages && obj.Enable_Local_Data)
{
obj.RestaurarDatosLocales();
}
}
}
}
@ -75,10 +108,47 @@ namespace CtrEditor.Serialization
if (selectedImage != null)
{
var settings = GetJsonSerializerSettings();
LoadCurrentPageState(selectedImage, settings);
// Paso 1: Cargar objetos globales
LoadAllPagesState(settings);
// Create UserControls for all loaded objects
// Paso 2: Cargar datos de la página actual
var simulationData = LoadCurrentPageState(selectedImage, settings);
// Paso 3: Crear snapshots de los objetos globales
// Nota: No filtramos por Enable_Local_Data aquí ya que se establecerá después
foreach (var obj in _mainViewModel.ObjetosSimulables)
{
if (obj.Enable_On_All_Pages)
{
obj.CrearSnapshotGlobal();
}
}
// Paso 4: Aplicar datos locales a objetos globales
if (simulationData?.DatosLocalesObjetos != null)
{
// Primero, desactivar Enable_Local_Data en todos los objetos globales
foreach (var obj in _mainViewModel.ObjetosSimulables.Where(o => o.Enable_On_All_Pages))
{
obj.Enable_Local_Data = false;
}
// Luego aplicar los datos locales, esto activará Enable_Local_Data automáticamente
foreach (var datosLocales in simulationData.DatosLocalesObjetos)
{
var objetoGlobal = _mainViewModel.ObjetosSimulables.FirstOrDefault(
o => o.Enable_On_All_Pages &&
o.Id.Value == datosLocales.Id_GlobalObject.Value);
if (objetoGlobal != null)
{
objetoGlobal.AplicarDatosLocales(datosLocales);
}
}
}
// Paso 5: Crear controles visuales
foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
{
if (objetoSimulable != null)
@ -95,17 +165,21 @@ namespace CtrEditor.Serialization
}
}
private void LoadCurrentPageState(string selectedImage, JsonSerializerSettings settings)
private SimulationData LoadCurrentPageState(string selectedImage, JsonSerializerSettings settings)
{
SimulationData simulationData = null;
string jsonPath = _datosDeTrabajo.ObtenerPathImagenConExtension(selectedImage, ".json");
if (File.Exists(jsonPath))
{
string jsonString = File.ReadAllText(jsonPath);
var simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
if (simulationData != null)
{
if (simulationData.ObjetosSimulables is not null)
_mainViewModel.ObjetosSimulables = simulationData.ObjetosSimulables;
{
foreach (var obj in simulationData.ObjetosSimulables)
_mainViewModel.ObjetosSimulables.Add(obj);
}
if (simulationData.PLC_ConnectionData is not null)
_mainViewModel.PLCViewModel = simulationData.PLC_ConnectionData;
@ -115,6 +189,7 @@ namespace CtrEditor.Serialization
PixelToMeter.Instance.calc = simulationData.UnitConverter;
}
}
return simulationData;
}
private void LoadAllPagesState(JsonSerializerSettings settings)
@ -158,5 +233,4 @@ namespace CtrEditor.Serialization
};
}
}
}
}