CtrEditor/MainWindow.xaml.cs

571 lines
23 KiB
C#
Raw Normal View History

using CtrEditor.ObjetosSim;
using System.Diagnostics;
using System.Globalization;
2024-05-01 14:45:20 -03:00
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
2025-02-18 14:08:55 -03:00
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using UserControl = System.Windows.Controls.UserControl;
2024-05-11 11:58:55 -03:00
2024-05-01 14:45:20 -03:00
namespace CtrEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// Para el Canvas
private Point _lastMousePosition;
private bool _isDrawingCanvas = false;
private bool _isDraggingCanvas = false;
private Image imagenDeFondo;
2025-02-18 14:08:55 -03:00
internal ObjectManipulationManager _objectManager;
2025-02-18 14:08:55 -03:00
// Temporizadores y animación
private DispatcherTimer _zoomTimer;
2024-06-09 16:26:09 -03:00
private double _targetZoomFactor;
private double _initialZoomFactor;
private double _currentZoomStep;
private Point _zoomCursorPosition;
private const int ZoomDuration = 500; // Duración del zoom en milisegundos
private int _ZoomDuration;
2024-06-09 16:26:09 -03:00
private const double MinZoomScale = 0.1; // Límite mínimo de zoom
private Stopwatch _stopwatch;
2025-02-18 14:08:55 -03:00
private dataDebug dataDebug = new dataDebug();
2024-05-01 14:45:20 -03:00
public MainWindow()
{
InitializeComponent();
2025-02-18 14:08:55 -03:00
_objectManager = new ObjectManipulationManager(this, ImagenEnTrabajoCanvas);
// Inicializar temporizador de zoom
2024-06-09 16:26:09 -03:00
_zoomTimer = new DispatcherTimer();
_zoomTimer.Interval = TimeSpan.FromMilliseconds(1);
_zoomTimer.Tick += ZoomTimer_Tick;
_stopwatch = new Stopwatch();
2025-02-18 14:08:55 -03:00
// Suscribir eventos
this.Loaded += MainWindow_Loaded;
ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
this.KeyDown += MainWindow_KeyDown;
2025-02-17 11:16:40 -03:00
ImagenEnTrabajoCanvas.MouseEnter += Canvas_MouseEnter;
2025-02-18 14:08:55 -03:00
this.Closed += MainWindow_Closed;
// Importante: Agregar el evento para el menú contextual
ImagenEnTrabajoCanvas.MouseRightButtonDown += Canvas_MouseRightButtonDown;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
if (DataContext is MainViewModel viewModel)
{
viewModel.MainWindow = this;
viewModel.ImageSelected += ViewModel_ImageSelected;
2025-02-18 14:08:55 -03:00
viewModel?.LoadInitialData();
viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
2024-05-31 14:25:24 -03:00
viewModel.MainCanvas = ImagenEnTrabajoCanvas;
}
}
public void SuscribirEventos(UserControl userControl)
{
2025-02-18 14:08:55 -03:00
_objectManager.SuscribirEventos(userControl);
}
public void AgregarRegistrarUserControlCanvas(UserControl userControl)
{
if (userControl is IDataContainer dataContainer)
{
SuscribirEventos(userControl);
Canvas.SetZIndex(userControl, ((int)dataContainer.ZIndex_Base() + dataContainer.zIndex_fromFrames));
ImagenEnTrabajoCanvas.Children.Add(userControl);
}
}
public void EliminarUserControlDelCanvas(UserControl userControl)
{
if (ImagenEnTrabajoCanvas.Children.Contains(userControl))
{
ImagenEnTrabajoCanvas.Children.Remove(userControl);
}
}
private void LoadImageToCanvas(string imagePath)
{
BitmapImage bitmap = new BitmapImage(new Uri(imagePath, UriKind.Absolute));
if (imagenDeFondo == null)
{
imagenDeFondo = new Image();
ImagenEnTrabajoCanvas.Children.Add(imagenDeFondo);
}
imagenDeFondo.Source = bitmap;
RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality);
// Elimina solo los ROIs, no la imagen de fondo
for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
{
if (ImagenEnTrabajoCanvas.Children[i] is not Image)
{
ImagenEnTrabajoCanvas.Children.RemoveAt(i);
}
}
ImagenEnTrabajoCanvas.Width = bitmap.Width;
ImagenEnTrabajoCanvas.Height = bitmap.Height;
Canvas.SetLeft(imagenDeFondo, 0);
Canvas.SetTop(imagenDeFondo, 0);
2024-05-01 14:45:20 -03:00
}
2024-05-02 11:06:45 -03:00
private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
{
if (_isDraggingCanvas)
{
_isDraggingCanvas = false;
2025-02-18 14:08:55 -03:00
ImagenEnTrabajoCanvas.ReleaseMouseCapture();
2025-02-18 17:52:27 -03:00
Mouse.OverrideCursor = null;
2025-02-17 11:16:40 -03:00
2025-02-18 17:52:27 -03:00
if (_objectManager.SelectedObjects.Count > 0)
2025-02-17 11:16:40 -03:00
{
2025-02-18 14:08:55 -03:00
_objectManager.MakeResizeRectanglesNormal();
2025-02-18 17:52:27 -03:00
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
2025-02-17 11:16:40 -03:00
}
2025-02-18 14:08:55 -03:00
e.Handled = true;
}
}
private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e)
{
2025-02-18 14:08:55 -03:00
if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas)
{
2025-02-18 17:52:27 -03:00
// Solo permitir el panning si el clic fue en el canvas o en la imagen de fondo
// y no en otros controles
if (e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo)
2025-02-17 11:16:40 -03:00
{
ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco
2025-02-18 14:08:55 -03:00
_isDraggingCanvas = true;
_lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
ImagenEnTrabajoCanvas.CaptureMouse();
2025-02-18 17:52:27 -03:00
Mouse.OverrideCursor = Cursors.Hand;
2025-02-18 14:08:55 -03:00
2025-02-17 11:16:40 -03:00
if (DataContext is MainViewModel viewModel)
{
2025-02-18 14:08:55 -03:00
viewModel.SelectedItemOsList = null;
_objectManager.RemoveResizeRectangles();
2025-02-17 11:16:40 -03:00
}
2025-02-18 14:08:55 -03:00
e.Handled = true;
2025-02-17 11:16:40 -03:00
}
}
}
private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e)
{
2025-02-18 14:08:55 -03:00
if (_isDraggingCanvas && e.LeftButton == MouseButtonState.Pressed)
{
var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
var dx = currentPosition.X - _lastMousePosition.X;
var dy = currentPosition.Y - _lastMousePosition.Y;
2025-02-18 14:08:55 -03:00
_objectManager.MakeResizeRectanglesTransparent();
_objectManager.RemoveHighlightRectangles();
2025-02-18 14:08:55 -03:00
var transform = (TranslateTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
.Children.First(t => t is TranslateTransform);
transform.X += dx;
transform.Y += dy;
_lastMousePosition = currentPosition;
2025-02-18 14:08:55 -03:00
e.Handled = true;
}
}
private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
2025-02-18 14:08:55 -03:00
_objectManager.MakeResizeRectanglesTransparent();
_objectManager.RemoveHighlightRectangles();
2025-02-18 14:08:55 -03:00
_initialZoomFactor = ((ScaleTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
.Children.First(t => t is ScaleTransform)).ScaleX;
2024-06-09 16:26:09 -03:00
double minZoomFactor = Math.Min(
ImagenEnTrabajoScrollViewer.ViewportWidth / ImagenEnTrabajoCanvas.ActualWidth,
ImagenEnTrabajoScrollViewer.ViewportHeight / ImagenEnTrabajoCanvas.ActualHeight);
2025-02-18 14:08:55 -03:00
_targetZoomFactor = e.Delta > 0 ?
_initialZoomFactor * 1.4 :
Math.Max(_initialZoomFactor * 0.75, minZoomFactor);
2024-06-09 16:26:09 -03:00
_zoomCursorPosition = e.GetPosition(ImagenEnTrabajoCanvas);
RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.LowQuality);
2025-02-18 14:08:55 -03:00
_ZoomDuration = !_zoomTimer.IsEnabled ? ZoomDuration : ZoomDuration / 3;
2024-06-09 16:26:09 -03:00
_stopwatch.Restart();
_zoomTimer.Start();
e.Handled = true;
}
private void ZoomTimer_Tick(object sender, EventArgs e)
{
double elapsedMilliseconds = _stopwatch.Elapsed.TotalMilliseconds;
2024-06-09 16:26:09 -03:00
if (elapsedMilliseconds >= _ZoomDuration)
{
_zoomTimer.Stop();
_stopwatch.Stop();
RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.HighQuality);
2025-02-18 17:52:27 -03:00
if (_objectManager.SelectedObjects.Count > 0)
2025-02-17 11:16:40 -03:00
{
2025-02-18 14:08:55 -03:00
_objectManager.MakeResizeRectanglesNormal();
2025-02-18 17:52:27 -03:00
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
2025-02-17 11:16:40 -03:00
}
2024-06-09 16:26:09 -03:00
return;
}
var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);
2024-06-09 16:26:09 -03:00
double t = elapsedMilliseconds / _ZoomDuration;
2025-02-18 14:08:55 -03:00
double easeOutT = t * (2 - t);
2024-06-09 16:26:09 -03:00
double zoomFactor = _initialZoomFactor + (_targetZoomFactor - _initialZoomFactor) * easeOutT;
zoomFactor = Math.Max(zoomFactor, MinZoomScale);
Point cursorPosition = _zoomCursorPosition;
var relativeX = cursorPosition.X * st.ScaleX + tt.X;
var relativeY = cursorPosition.Y * st.ScaleY + tt.Y;
2024-06-09 16:26:09 -03:00
st.ScaleX = zoomFactor;
st.ScaleY = zoomFactor;
tt.X = relativeX - cursorPosition.X * st.ScaleX;
tt.Y = relativeY - cursorPosition.Y * st.ScaleY;
}
2025-02-18 14:08:55 -03:00
private void ListaOs_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco
2025-02-18 14:08:55 -03:00
UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion);
if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject)
{
// Siempre trabajar con selección única para las propiedades
CargarPropiedadesosDatos(selectedObject);
// No modificar la selección múltiple aquí, solo actualizar los rectángulos de manipulación
// si el objeto seleccionado no está en la selección actual
if (!_objectManager.SelectedObjects.Contains(selectedObject))
{
if (!((MainViewModel)DataContext).IsMultiSelectionActive)
{
_objectManager.ClearSelection();
_objectManager.SelectObject(selectedObject);
}
}
}
else
{
_objectManager.RemoveResizeRectangles();
}
}
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
// Only force canvas focus if PanelEdicion doesn't have focus
if (!PanelEdicion.IsKeyboardFocusWithin)
{
if (!ImagenEnTrabajoCanvas.IsFocused)
{
ImagenEnTrabajoCanvas.Focus();
}
}
2025-02-18 14:08:55 -03:00
if (DataContext is MainViewModel viewModel)
{
if (e.Key == Key.Delete)
{
_objectManager.EliminarObjetosSeleccionados();
2025-02-18 14:08:55 -03:00
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
viewModel.SelectedItemOsList = null;
_objectManager.ClearSelection();
_objectManager.RemoveResizeRectangles();
e.Handled = true;
}
else if (_objectManager.SelectedObjects.Any())
{
const float moveDistance = 0.1f;
switch (e.Key)
{
case Key.Left:
MoveSelectedObjects(-moveDistance, 0);
e.Handled = true;
break;
case Key.Right:
MoveSelectedObjects(moveDistance, 0);
e.Handled = true;
break;
case Key.Up:
MoveSelectedObjects(0, -moveDistance);
e.Handled = true;
break;
case Key.Down:
MoveSelectedObjects(0, moveDistance);
e.Handled = true;
break;
}
}
}
}
private void MoveSelectedObjects(float deltaX, float deltaY)
{
// Mover todos los objetos primero
foreach (var obj in _objectManager.SelectedObjects)
{
obj.Left += deltaX;
obj.Top += deltaY;
}
// Forzar una actualización del layout antes de actualizar los visuales
ImagenEnTrabajoCanvas.UpdateLayout();
// Ahora actualizar los visuales de selección
_objectManager.UpdateSelectionVisuals();
if (DataContext is MainViewModel viewModel)
{
viewModel.HasUnsavedChanges = true;
2025-02-18 14:08:55 -03:00
}
}
private void Canvas_MouseEnter(object sender, MouseEventArgs e)
{
if (e.OriginalSource == ImagenEnTrabajoCanvas)
{
//_objectManager.RemoveResizeRectangles();
}
}
private void MainWindow_Closed(object sender, EventArgs e)
{
if (DataContext is MainViewModel viewModel)
{
viewModel.ImageSelected -= ViewModel_ImageSelected;
}
}
private void CargarPropiedadesosDatos(osBase selectedObject)
{
if (DataContext is MainViewModel viewModel)
viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
}
public (float X, float Y) ObtenerCentroCanvasMeters()
{
var c = ObtenerCentroCanvasPixels();
return (PixelToMeter.Instance.calc.PixelsToMeters(c.X),
PixelToMeter.Instance.calc.PixelsToMeters(c.Y));
}
public (float X, float Y) ObtenerCentroCanvasPixels()
{
var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);
double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth;
double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight;
double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset;
double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset;
double centerX = offsetX + (visibleWidth / 2);
double centerY = offsetY + (visibleHeight / 2);
double canvasCenterX = (centerX - tt.X) / st.ScaleX;
double canvasCenterY = (centerY - tt.Y) / st.ScaleY;
return ((float)canvasCenterX, (float)canvasCenterY);
}
2025-02-18 14:08:55 -03:00
private void ViewModel_ImageSelected(object sender, string imagePath)
{
2025-02-18 14:08:55 -03:00
LoadImageToCanvas(imagePath);
}
2025-02-18 14:08:55 -03:00
public void DebugWindow()
{
2025-02-18 14:08:55 -03:00
var debugWindow = new wDebug
{
2025-02-18 14:08:55 -03:00
Data = dataDebug
};
debugWindow.Show();
}
2024-05-02 11:06:45 -03:00
2025-02-18 14:08:55 -03:00
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
2024-06-11 14:43:12 -03:00
{
2025-02-18 14:08:55 -03:00
// Aceptar el evento si viene del canvas o de la imagen de fondo
if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo || e.Source is UserControl) &&
2025-02-18 17:52:27 -03:00
DataContext is MainViewModel viewModel)
2025-02-17 11:16:40 -03:00
{
ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco
2025-02-18 17:52:27 -03:00
e.Handled = true;
2025-02-18 14:08:55 -03:00
ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas));
}
2024-06-11 14:43:12 -03:00
}
2025-02-18 14:08:55 -03:00
private void ShowContextMenu(Point position)
{
2025-02-18 14:08:55 -03:00
var contextMenu = new ContextMenu();
var multiSelectMenuItem = new MenuItem
{
2025-02-18 14:08:55 -03:00
Header = "Modo Multi-Selección",
IsCheckable = true,
2025-02-18 17:52:27 -03:00
StaysOpenOnClick = false
2025-02-18 14:08:55 -03:00
};
2025-02-17 11:16:40 -03:00
if (DataContext is MainViewModel viewModel)
{
2025-02-18 14:08:55 -03:00
multiSelectMenuItem.IsChecked = viewModel.IsMultiSelectionActive;
multiSelectMenuItem.Click += (s, e) =>
2025-02-17 11:16:40 -03:00
{
2025-02-18 14:08:55 -03:00
viewModel.IsMultiSelectionActive = multiSelectMenuItem.IsChecked;
};
2025-02-18 17:52:27 -03:00
// Solo mostrar opciones de alineación si hay objetos seleccionados
if (_objectManager.SelectedObjects.Count > 1)
{
var alignmentMenu = new MenuItem { Header = "Alinear" };
var sizeMenu = new MenuItem { Header = "Igualar Tamaño" };
var joinMenu = new MenuItem { Header = "Unir" };
// Opciones de alineación
2025-02-18 17:52:27 -03:00
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear a la Izquierda", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Left)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear a la Derecha", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Right)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear Arriba", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Top)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear Abajo", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Bottom)) });
alignmentMenu.Items.Add(new Separator());
alignmentMenu.Items.Add(new MenuItem { Header = "Centrar Horizontalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.CenterHorizontally)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Centrar Verticalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.CenterVertically)) });
alignmentMenu.Items.Add(new Separator());
alignmentMenu.Items.Add(new MenuItem { Header = "Distribuir Horizontalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.DistributeHorizontally)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Distribuir Verticalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.DistributeVertically)) });
// Opciones de igualar tamaño
sizeMenu.Items.Add(new MenuItem { Header = "Igualar Ancho", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.EqualWidth)) });
sizeMenu.Items.Add(new MenuItem { Header = "Igualar Alto", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.EqualHeight)) });
sizeMenu.Items.Add(new MenuItem { Header = "Igualar Ángulo", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.EqualAngle)) });
// Opciones de unir
joinMenu.Items.Add(new MenuItem { Header = "Unir Horizontalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.JoinHorizontally)) });
joinMenu.Items.Add(new MenuItem { Header = "Unir Verticalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.JoinVertically)) });
2025-02-18 17:52:27 -03:00
contextMenu.Items.Add(alignmentMenu);
contextMenu.Items.Add(sizeMenu);
contextMenu.Items.Add(joinMenu);
2025-02-18 17:52:27 -03:00
contextMenu.Items.Add(new Separator());
}
2025-02-17 11:16:40 -03:00
contextMenu.Items.Add(multiSelectMenuItem);
contextMenu.PlacementTarget = ImagenEnTrabajoCanvas;
contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
contextMenu.IsOpen = true;
}
}
private void Canvas_KeyDown(object sender, KeyEventArgs e)
{
// Only handle if PanelEdicion doesn't have focus
if (!PanelEdicion.IsKeyboardFocusWithin)
{
HandleKeyDown(e);
}
}
private void ScrollViewer_PreviewKeyDown(object sender, KeyEventArgs e)
{
// 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;
}
}
private void HandleKeyDown(KeyEventArgs e)
{
if (DataContext is MainViewModel viewModel)
{
if (e.Key == Key.Delete)
{
_objectManager.EliminarObjetosSeleccionados(); // Cambiar aquí
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
viewModel.SelectedItemOsList = null;
_objectManager.ClearSelection();
_objectManager.RemoveResizeRectangles();
e.Handled = true;
}
else if (_objectManager.SelectedObjects.Any())
{
const float moveDistance = 0.01f;
switch (e.Key)
{
case Key.Left:
MoveSelectedObjects(-moveDistance, 0);
e.Handled = true;
break;
case Key.Right:
MoveSelectedObjects(moveDistance, 0);
e.Handled = true;
break;
case Key.Up:
MoveSelectedObjects(0, -moveDistance);
e.Handled = true;
break;
case Key.Down:
MoveSelectedObjects(0, moveDistance);
e.Handled = true;
break;
}
}
}
}
2024-05-01 14:45:20 -03:00
}
2024-05-11 11:58:55 -03:00
public class FloatValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (string.IsNullOrEmpty(value?.ToString()))
return new ValidationResult(false, "El campo no puede estar vacío.");
if (float.TryParse(value.ToString(), NumberStyles.Float, cultureInfo, out float result))
2025-02-18 14:08:55 -03:00
return ValidationResult.ValidResult;
2024-05-11 11:58:55 -03:00
else
return new ValidationResult(false, "Ingrese un número válido.");
}
}
2024-05-01 14:45:20 -03:00
}