using Newtonsoft.Json; using System.Windows.Controls; using CtrEditor.Simulacion; using System.Reflection; using System.Windows.Data; using System.Windows; using System.Windows.Media; using CtrEditor.ObjetosSim.UserControls; using System.Collections; using System.Windows.Input; using System.Windows.Shapes; using Xceed.Wpf.Toolkit.PropertyGrid; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using Xceed.Wpf.Toolkit; using Xceed.Wpf.Toolkit.PropertyGrid.Editors; using CtrEditor.ObjetosSim.Extraccion_Datos; using System.Windows.Controls.Primitives; namespace CtrEditor.ObjetosSim { public static class UserControlFactory { public static UserControl? GetControlForType(Type tipoObjeto) { // Obtener el nombre del tipo de objeto string typeName = tipoObjeto.Name; // Cambiar las primeras dos letras de 'os' a 'uc' if (typeName.StartsWith("os")) { string newTypeName = "uc" + typeName.Substring(2); // Obtener el ensamblado donde se encuentra el tipo UserControl Assembly assembly = Assembly.GetExecutingAssembly(); // Buscar el tipo en los ensamblados cargados Type? controlType = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) .FirstOrDefault(t => t.Name == newTypeName); if (controlType != null && typeof(UserControl).IsAssignableFrom(controlType)) { // Crear una instancia del tipo encontrado return (UserControl?)Activator.CreateInstance(controlType); } } return null; } public static osBase? GetInstanceForType(Type tipoObjeto) { // Verifica si el tipo pasado es un subtipo de osBase if (!typeof(osBase).IsAssignableFrom(tipoObjeto)) { throw new ArgumentException("El tipo pasado no es un subtipo de osBase", nameof(tipoObjeto)); } // Crear una instancia del tipo especificado osBase obj = (osBase?)Activator.CreateInstance(tipoObjeto); obj.InicializaNuevoObjeto(); return obj; } public static osBase? CreateInstanceAndPopulate(Type tipoObjeto, string jsonString) { osBase? instance = GetInstanceForType(tipoObjeto); if (instance != null) { // Deserializa los datos desde jsonString y popula la instancia JsonConvert.PopulateObject(jsonString, instance); } return instance; } public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerFP simulationManager) { if (userControl is IDataContainer dataContainer) { dataContainer.Datos = datos; userControl.DataContext = datos; datos.VisualRepresentation = userControl; datos.simulationManager = simulationManager; } } public static void LimpiarPropiedadesosDatos(PropertyGrid propertyGrid) { // Forzar la actualización de bindings pendientes antes de limpiar ForzarActualizacionBindings(propertyGrid); // Clear previous properties propertyGrid.SelectedObject = null; propertyGrid.PropertyDefinitions.Clear(); } public static void ForzarActualizacionBindings(PropertyGrid propertyGrid) { try { // Método 1: Forzar el foco fuera del PropertyGrid para activar LostFocus if (propertyGrid.IsKeyboardFocusWithin) { // Crear un elemento temporal para robar el foco var tempButton = new System.Windows.Controls.Button(); var parent = propertyGrid.Parent as Panel; if (parent != null) { parent.Children.Add(tempButton); tempButton.Focus(); parent.Children.Remove(tempButton); } else { // Alternativa: mover el foco al PropertyGrid mismo propertyGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); } } // Método 2: Forzar la actualización de todos los bindings del PropertyGrid var bindingExpression = BindingOperations.GetBindingExpression(propertyGrid, PropertyGrid.SelectedObjectProperty); bindingExpression?.UpdateSource(); // Método 3: Buscar controles de edición activos y forzar su actualización ForzarActualizacionControlesEditores(propertyGrid); // Pequeña pausa para permitir que se procesen los eventos System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Background, new Action(() => { })); } catch (Exception ex) { // Log del error si es necesario, pero no interrumpir el flujo System.Diagnostics.Debug.WriteLine($"Error al forzar actualización de bindings: {ex.Message}"); } } private static void ForzarActualizacionControlesEditores(DependencyObject parent) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); // Buscar TextBox, ComboBox, y otros controles de edición comunes if (child is TextBox textBox) { var expression = textBox.GetBindingExpression(TextBox.TextProperty); expression?.UpdateSource(); } else if (child is ComboBox comboBox) { var expression = comboBox.GetBindingExpression(ComboBox.SelectedValueProperty); expression?.UpdateSource(); var textExpression = comboBox.GetBindingExpression(ComboBox.TextProperty); textExpression?.UpdateSource(); } else if (child is CheckBox checkBox) { var expression = checkBox.GetBindingExpression(CheckBox.IsCheckedProperty); expression?.UpdateSource(); } // Recursión para buscar en controles hijos ForzarActualizacionControlesEditores(child); } } public static void CargarPropiedadesosDatos(osBase selectedObject, PropertyGrid propertyGrid) { // Forzar la actualización de bindings pendientes antes de cambiar el objeto ForzarActualizacionBindings(propertyGrid); // Limpia las propiedades previas propertyGrid.SelectedObject = null; propertyGrid.PropertyDefinitions.Clear(); // Obtén las propiedades del objeto (excluyendo las que tengan HiddenAttribute) var properties = TypeDescriptor.GetProperties(selectedObject) .Cast() .Where(prop => !prop.Attributes.OfType().Any()) .OrderBy(prop => prop.Name); foreach (var property in properties) { if (property.Name.EndsWith("_oculto")) continue; var displayNameAttr = property.Attributes.OfType().FirstOrDefault(); var customNameAttr = property.Attributes.OfType().FirstOrDefault(); string displayName; if (customNameAttr != null) { displayName = customNameAttr.DisplayName; } else if (displayNameAttr != null) { displayName = displayNameAttr.DisplayName; } else { displayName = property.Name.Replace("_", " "); } var propertyDefinition = new PropertyDefinition { TargetProperties = new[] { property.Name }, DisplayName = displayName }; // Aquí se añaden todas las propiedades; para "ImagePath" no se requiere // ninguna configuración adicional, pues el EditorTemplateDefinition en XAML se // aplicará automáticamente. if (property.PropertyType == typeof(double) || property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || property.PropertyType == typeof(bool) || property.PropertyType == typeof(osBase) || property.PropertyType == typeof(osVMmotorSim) || property.PropertyType == typeof(osBuscarCoincidencias) || property.PropertyType == typeof(Color)) { propertyGrid.PropertyDefinitions.Add(propertyDefinition); } } propertyGrid.SelectedObject = selectedObject; } } }