diff --git a/MainViewModel.cs b/MainViewModel.cs index 7bf3740..165d00f 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -386,7 +386,8 @@ namespace CtrEditor assignImagesViewModel.Initialize(this, assignImagesWindow); assignImagesWindow.DataContext = assignImagesViewModel; assignImagesWindow.ShowDialog(); - SaveStateObjetosSimulables(); + if (assignImagesWindow.DataContext is AssignImagesViewModel dialog && dialog.CloseOK) + SaveStateObjetosSimulables(); } private async Task WaitForUIUpdateAsync() @@ -398,7 +399,10 @@ namespace CtrEditor private async void MultiPageExtractTagsCommand() { - var ImagenesSeleccionadas = new ObservableCollection(); + var ImagenesSeleccionadas = new ObservableCollection + { + SelectedImage + }; StopSimulation(); @@ -408,17 +412,21 @@ namespace CtrEditor selectPagesWindow.DataContext = selectPagesViewModel; selectPagesWindow.ShowDialog(); - foreach (var page in ImagenesSeleccionadas) - { - SelectedImage = page; - await WaitForUIUpdateAsync(); // Espera a que la UI se actualice - ExtraerTags(); - } + 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(); + var ImagenesSeleccionadas = new ObservableCollection + { + SelectedImage + }; StopSimulation(); @@ -446,7 +454,8 @@ namespace CtrEditor { foreach (var obj in ObjetosSimulables) if (obj is osBuscarCoincidencias objBC) - objBC.BuscarCoincidencias(); + if (objBC.Show_On_This_Page) + objBC.BuscarCoincidencias(); } @@ -462,7 +471,6 @@ namespace CtrEditor try { - int colFix = 0; // Crea o abre un libro de Excel. XLWorkbook workbook = File.Exists(filePath) ? new XLWorkbook(filePath) : new XLWorkbook(); var sheetName = "TagsExtracted"; @@ -470,53 +478,96 @@ namespace CtrEditor 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 row = lastRowUsed == null ? 2 : lastRowUsed.RowNumber() + 1; + int rowOffset = lastRowUsed == null ? 2 : lastRowUsed.RowNumber() + 1; // Determina la columna fija más alta. - foreach (var obj in ObjetosSimulables) - { - if (obj is osExtraccionTag objExtraccionTag && (objExtraccionTag.Id_Search_Templates == null || objExtraccionTag.Id_Search_Templates == "") && !objExtraccionTag.Cloned) + 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().ToList(); + var osExtraccionTagBaseGrouped_List = ObjetosSimulables + .OfType() + .Where(tag => !tag.Cloned && tag.Id_Search_Templates != null && tag.Id_Search_Templates != "") + .ToList(); + var osExtraccionTagBaseFix_List = ObjetosSimulables + .OfType() + .Where(tag => !tag.Cloned && (tag.Id_Search_Templates == null || tag.Id_Search_Templates == "")) + .ToList(); + + var osExtraccionTagCloned_List = ObjetosSimulables + .OfType() + .Where(tag => 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) { - colFix = Math.Max(colFix, objExtraccionTag.Collumn_number); + 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 colNextGroup = 0; - - // Itera sobre los objetos simulables para extraer y guardar las etiquetas. - foreach (var obj in ObjetosSimulables) - { - if (obj is osBuscarCoincidencias objBC) - { - int maxColGroup = 0; - - foreach (var objchild in ObjetosSimulables) + // 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) { - if (objchild is osExtraccionTag objExtraccionTag && objExtraccionTag.Id_Search_Templates == objBC.Nombre && objExtraccionTag.Cloned) - { - foreach (var objfix in ObjetosSimulables) - { - if (objfix is osExtraccionTag objExtraccionTagNoGroup && (objExtraccionTagNoGroup.Id_Search_Templates == null || objExtraccionTagNoGroup.Id_Search_Templates == "") && !objExtraccionTagNoGroup.Cloned) - { - if (worksheet.Cell(1, objExtraccionTagNoGroup.Collumn_number).IsEmpty()) - worksheet.Cell(1, objExtraccionTagNoGroup.Collumn_number).Value = objExtraccionTagNoGroup.Collumn_name; - objExtraccionTagNoGroup.CaptureImageAreaAndDoOCR(); - worksheet.Cell(row, objExtraccionTagNoGroup.Collumn_number).Value = objExtraccionTagNoGroup.Tag_extract; - } - } - objExtraccionTag.CaptureImageAreaAndDoOCR(); - worksheet.Cell(row, objExtraccionTag.Collumn_number + colFix + colNextGroup).Value = objExtraccionTag.Tag_extract; - if (worksheet.Cell(1, objExtraccionTag.Collumn_number + colFix + colNextGroup).IsEmpty()) - worksheet.Cell(1, objExtraccionTag.Collumn_number + colFix + colNextGroup).Value = objExtraccionTag.Collumn_name; + col = objExtraccionTag.Collumn_number; + if (col == 0 || columnasOcupadas.Contains(col)) + col = ++actualMaxCol; + else + actualMaxCol = Math.Max(actualMaxCol, col); - maxColGroup = Math.Max(maxColGroup, objExtraccionTag.Collumn_number); - if (objExtraccionTag.New_Row) row++; - } + 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; } - colNextGroup += maxColGroup; } } + // Formatear los títulos en la fila 1 var titleRow = worksheet.Row(1); titleRow.Style.Font.Bold = true; diff --git a/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs b/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs index 4268f77..64ae972 100644 --- a/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs +++ b/ObjetosSim/Extraccion Datos/ucBuscarCoincidencias.xaml.cs @@ -145,7 +145,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [ObservableProperty] [property: Category("Tag Extraction:")] [property: ReadOnly(true)] - float coincidencias; + int coincidencias; public osBuscarCoincidencias() { @@ -278,7 +278,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos search_rectangles = new List(); // Añadir el rectángulo usado por croppedBitmap a search_rectangles - search_rectangles.Add(new Rect(x / scaleFactorX, y / scaleFactorY, width / scaleFactorX, height / scaleFactorY)); + //search_rectangles.Add(new Rect(x / scaleFactorX, y / scaleFactorY, width / scaleFactorX, height / scaleFactorY)); // Obtener los puntos que superan el umbral float[] resultArray = result.GetData(false) as float[]; @@ -349,9 +349,8 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos var objetosSimulables2Copy = new List(_mainViewModel.ObjetosSimulables); // Saltar el primer rectángulo en el foreach - - - foreach (var rectangle in search_rectangles.Skip(1)) + int Row = 0; + foreach (var rectangle in search_rectangles) //.Skip(1)) { float offsetX = PixelsToMeters((float)rectangle.X) - Left; float offsetY = PixelsToMeters((float)rectangle.Y) - Top; @@ -368,6 +367,8 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos if (newObj != null) { newObj.Cloned = true; + newObj.Cloned_from = objExtraccionTag.Id; + newObj.Copy_Number = Row; newObj.Enable_On_All_Pages = false; if (newObj.Extraer) objExtraccionTag.CaptureImageAreaAndDoOCR(); @@ -375,6 +376,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos } } } + Row++; if (newObj != null) newObj.New_Row = true; diff --git a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml index 449e897..b387e2e 100644 --- a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml +++ b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml @@ -13,15 +13,23 @@ - - - - + + + + diff --git a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs index 037d23d..bb65f0a 100644 --- a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs +++ b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs @@ -38,6 +38,12 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [property: Category("Tag Extraction:")] bool cloned; + [ObservableProperty] + [property: Description("Autocreated and cloned with Search Templates")] + [property: Category("Tag Extraction:")] + [property: Hidden] + UniqueId cloned_from; + [ObservableProperty] bool new_Row; @@ -76,7 +82,18 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos ResetTimer(); } + [ObservableProperty] + [property: Category("Layout:")] + public float angulo; + + partial void OnAnguloChanged(float value) + { + ResetTimer(); + } + public override void OnTimerAfterMovement() { + Angulo = (float)Math.Round(Angulo / 90) * 90; + if (Extraer) CaptureImageAreaAndDoOCR(); } @@ -110,10 +127,6 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos } } - [ObservableProperty] - [property: Category("Layout:")] - public float angulo; - [ObservableProperty] [property: Category("Tag Extraction:")] string tag_extract; @@ -131,7 +144,17 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [property: Category("Export:")] int collumn_number; - [ObservableProperty] + [ObservableProperty] + [property: Category("Tag Extraction:")] + [property: ReadOnly(true)] + int copy_Number; + + [ObservableProperty] + [property: Category("Tag Extraction:")] + bool show_Debug_Window; + + + [ObservableProperty] float opacity_oculto; public osExtraccionTag() @@ -144,7 +167,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos public void CaptureImageAreaAndDoOCR() { - Tag_extract = CaptureImageAreaAndDoOCR(Left, Top, Ancho, Alto); + Tag_extract = CaptureImageAreaAndDoOCR(Left, Top, Ancho, Alto, Angulo, Show_Debug_Window); } public int ExportToExcel(IXLWorksheet worksheet, int row, int colBase) diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 00a9b87..4818cba 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -179,57 +179,74 @@ namespace CtrEditor.ObjetosSim } - public string CaptureImageAreaAndDoOCR(float Left, float Top, float Ancho, float Alto) + public string CaptureImageAreaAndDoOCR(float Left, float Top, float Ancho, float Alto, float Angulo = 0, bool ShowPreview = false) { if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo) { - // Asegurarse de que la imagen origen está disponible if (imagenDeFondo.Source is BitmapSource bitmapSource) { - // Obtener los DPI de la imagen original float originalDpiX = (float)bitmapSource.DpiX; float originalDpiY = (float)bitmapSource.DpiY; - // Estándar DPI en el que el Canvas renderiza la imagen - float canvasDpiX = 96; // WPF usually renders at 96 DPI + float canvasDpiX = 96; float canvasDpiY = 96; - // Calcular el ratio de escala entre el Canvas y la imagen original float scaleFactorX = originalDpiX / canvasDpiX; float scaleFactorY = originalDpiY / canvasDpiY; - // Ajustar las coordenadas de recorte en función del ratio de escala int x = (int)MeterToPixels(Left * scaleFactorX); int y = (int)MeterToPixels(Top * scaleFactorY); int width = (int)MeterToPixels(Ancho * scaleFactorX); int height = (int)MeterToPixels(Alto * scaleFactorY); - // Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen if (x < 0) x = 0; if (y < 0) y = 0; if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x; if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y; - // Recortar el área deseada utilizando las coordenadas ajustadas CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height)); - // Codificar el bitmap recortado a un MemoryStream + TransformedBitmap transformedBitmap = new TransformedBitmap(); + transformedBitmap.BeginInit(); + transformedBitmap.Source = croppedBitmap; + + if (Angulo != 0) + { + RotateTransform rotateTransform = new RotateTransform(-Angulo); + transformedBitmap.Transform = rotateTransform; + } + + transformedBitmap.EndInit(); + PngBitmapEncoder encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(croppedBitmap)); + encoder.Frames.Add(BitmapFrame.Create(transformedBitmap)); using (MemoryStream memoryStream = new MemoryStream()) { encoder.Save(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); - //ShowPreviewWindow(memoryStream); + if (ShowPreview) ShowPreviewWindow(memoryStream); - // Cargar la imagen en Tesseract desde el MemoryStream - using (var img = Pix.LoadFromMemory(memoryStream.ToArray())) - using (var engine = new TesseractEngine(@"./Tesseract", "eng", EngineMode.Default)) + using (var bmp = new System.Drawing.Bitmap(memoryStream)) { - var result = engine.Process(img); - return result.GetText(); + int targetDpi = 400; + var resizedBmp = new System.Drawing.Bitmap(bmp, new System.Drawing.Size(bmp.Width * targetDpi / (int)originalDpiX, bmp.Height * targetDpi / (int)originalDpiY)); + + using (var msResized = new MemoryStream()) + { + resizedBmp.Save(msResized, System.Drawing.Imaging.ImageFormat.Png); + msResized.Seek(0, SeekOrigin.Begin); + + using (var img = Pix.LoadFromMemory(msResized.ToArray())) + using (var engine = new TesseractEngine(@"./Tesseract", "eng", EngineMode.Default)) + { + // Configuraciones para mejorar el OCR de una sola letra + engine.SetVariable("tessedit_char_whitelist", " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-."); // Lista blanca de caracteres + var result = engine.Process(img); + return result.GetText(); + } + } } } } @@ -237,6 +254,7 @@ namespace CtrEditor.ObjetosSim return ""; } + // All Pages Objects [NotifyPropertyChangedFor(nameof(Show_On_This_Page))] [ObservableProperty] @@ -817,6 +835,7 @@ namespace CtrEditor.ObjetosSim public class UniqueId { public int Value { get; set; } + public UniqueId ObtenerNuevaID() { Value = EstadoPersistente.Instance.newid; @@ -824,13 +843,64 @@ namespace CtrEditor.ObjetosSim Value++; return this; } + public void NoId() { // No ID == NULL Value = 0; } + + // Sobrecarga del operador ++ + public static UniqueId operator ++(UniqueId id) + { + if (id == null) + { + id = new UniqueId(); + } + + id.Value = EstadoPersistente.Instance.newid; + if (id.Value == 0) + id.Value++; + + return id; + } + + // Sobrecarga del operador == + public static bool operator ==(UniqueId id1, UniqueId id2) + { + if (ReferenceEquals(id1, null) || ReferenceEquals(id2, null)) + return false; + + return id1.Value == id2.Value; + } + + // Sobrecarga del operador != + public static bool operator !=(UniqueId id1, UniqueId id2) + { + if (ReferenceEquals(id1, null) || ReferenceEquals(id2, null)) + return true; + + return id1.Value != id2.Value; + } + + // Sobrescribir Equals y GetHashCode también es una buena práctica + public override bool Equals(object obj) + { + if (obj is UniqueId id) + { + return Value == id.Value; + } + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } + + public class osBaseItemsSource : IItemsSource { public ItemCollection GetValues() diff --git a/PopUps/AssignImagesWindow.xaml b/PopUps/AssignImagesWindow.xaml index 7d12cf3..6f7f1dc 100644 --- a/PopUps/AssignImagesWindow.xaml +++ b/PopUps/AssignImagesWindow.xaml @@ -58,13 +58,9 @@ - - - - - - + + diff --git a/PopUps/AssignImagesWindow.xaml.cs b/PopUps/AssignImagesWindow.xaml.cs index e46eb8d..5cb2c97 100644 --- a/PopUps/AssignImagesWindow.xaml.cs +++ b/PopUps/AssignImagesWindow.xaml.cs @@ -1,13 +1,9 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CtrEditor.ObjetosSim; -using CtrEditor; using System.Collections.ObjectModel; using System.Windows; -using System.Windows.Controls; -using System.Collections; using CtrEditor.ObjetosSim.Extraccion_Datos; -using Microsoft.Xaml.Behaviors; namespace CtrEditor.PopUps @@ -16,18 +12,19 @@ namespace CtrEditor.PopUps /// Interaction logic for AssignImagesWindow.xaml /// public partial class AssignImagesWindow : Window - { + { public AssignImagesWindow() { InitializeComponent(); } + } public partial class AssignImagesViewModel : ObservableObject { private MainViewModel _mainViewModel; private Window _window; - + private bool _closeOK; [ObservableProperty] private ObservableCollection objetosSimulables; @@ -40,7 +37,11 @@ namespace CtrEditor.PopUps [ObservableProperty] private ObservableCollection selectedImagenes; - public AssignImagesViewModel() { } + public AssignImagesViewModel() + { + SelectedObjetosSimulables = new ObservableCollection(); + SelectedObjetosSimulables.CollectionChanged += SelectedObjetosSimulables_CollectionChanged; + } public void Initialize(MainViewModel mainViewModel, Window window) { @@ -50,8 +51,26 @@ namespace CtrEditor.PopUps o => o.Enable_On_All_Pages && ((o is osExtraccionTag ex && !ex.Cloned) || (o is osBuscarCoincidencias)))); ListaImagenes = _mainViewModel.ListaImagenes; - SelectedObjetosSimulables = new ObservableCollection(); - SelectedImagenes = new ObservableCollection(); + } + + private void SelectedObjetosSimulables_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + UpdateSelectedImages(); + } + + private void UpdateSelectedImages() + { + var selectedImages = new HashSet(); + + foreach (var objeto in SelectedObjetosSimulables) + { + foreach (var image in objeto.ShowOnThisPagesList) + { + selectedImages.Add(image); + } + } + + SelectedImagenes = new ObservableCollection(selectedImages); } [RelayCommand] @@ -62,7 +81,7 @@ namespace CtrEditor.PopUps objeto.ShowOnThisPagesList = new List(SelectedImagenes); objeto.Show_On_This_Page = objeto.Show_On_This_Page; } - + _closeOK = true; _window.Close(); } @@ -97,67 +116,11 @@ namespace CtrEditor.PopUps { SelectedImagenes.Clear(); } + + public bool CloseOK => _closeOK; } - public class SelectedItemsBehavior : Behavior - { - public IList SelectedItems - { - get { return (IList)GetValue(SelectedItemsProperty); } - set { SetValue(SelectedItemsProperty, value); } - } - - public static readonly DependencyProperty SelectedItemsProperty = - DependencyProperty.Register("SelectedItems", typeof(IList), typeof(SelectedItemsBehavior), new PropertyMetadata(null, OnSelectedItemsChanged)); - - protected override void OnAttached() - { - base.OnAttached(); - AssociatedObject.SelectionChanged += OnSelectionChanged; - } - - protected override void OnDetaching() - { - base.OnDetaching(); - AssociatedObject.SelectionChanged -= OnSelectionChanged; - } - - private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var behavior = d as SelectedItemsBehavior; - behavior?.UpdateSelectedItems(); - } - - private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (SelectedItems != null) - { - foreach (var item in e.RemovedItems) - { - SelectedItems.Remove(item); - } - foreach (var item in e.AddedItems) - { - SelectedItems.Add(item); - } - } - } - - private void UpdateSelectedItems() - { - if (SelectedItems != null) - { - AssociatedObject.SelectionChanged -= OnSelectionChanged; - AssociatedObject.SelectedItems.Clear(); - foreach (var item in SelectedItems) - { - AssociatedObject.SelectedItems.Add(item); - } - AssociatedObject.SelectionChanged += OnSelectionChanged; - } - } - } } diff --git a/PopUps/SelectPages.xaml.cs b/PopUps/SelectPages.xaml.cs index 55be2b9..5d05e55 100644 --- a/PopUps/SelectPages.xaml.cs +++ b/PopUps/SelectPages.xaml.cs @@ -39,6 +39,8 @@ public partial class SelectPagesViewModel : ObservableObject private Window _window; private ObservableCollection _imagenesSeleccionadas; + private bool _closeOK; + [ObservableProperty] private ObservableCollection listaImagenes; @@ -59,7 +61,7 @@ public partial class SelectPagesViewModel : ObservableObject [RelayCommand] private void AssignImages() { - + _closeOK = true; _window.Close(); } @@ -79,4 +81,6 @@ public partial class SelectPagesViewModel : ObservableObject SelectedImagenes.Clear(); } + public bool CloseOK => _closeOK; + } \ No newline at end of file