Se mejoró la funcionalidad de renombrado de imágenes en la interfaz, integrando un PropertyGrid para editar propiedades de imágenes, incluyendo etiquetas. Se actualizó la lógica para eliminar entradas vacías y se modificó el diseño de la ventana de renombrado para una mejor experiencia de usuario. Además, se implementó un editor de etiquetas que permite gestionar etiquetas de manera más eficiente.

This commit is contained in:
Miguel 2025-06-18 15:20:26 +02:00
parent 909e438f5b
commit 354b4a8acf
7 changed files with 206 additions and 52 deletions

View File

@ -416,37 +416,26 @@ namespace CtrEditor
if (string.IsNullOrEmpty(imageName)) return;
var imageData = GetOrCreateImageData(imageName);
var currentCustomName = imageData.CustomName;
var dialog = new PopUps.RenameImageWindow(imageName, currentCustomName);
var dialog = new PopUps.RenameImageWindow(imageName, imageData);
dialog.Owner = MainWindow;
if (dialog.ShowDialog() == true)
{
string newName = dialog.NewImageName?.Trim() ?? string.Empty;
if (newName != currentCustomName)
// El dialog ya ha modificado directamente el imageData
// Solo necesitamos verificar si debemos remover la entrada si está vacía
if (string.IsNullOrEmpty(imageData.CustomName) &&
imageData.Tags.Count == 0 &&
string.IsNullOrEmpty(imageData.Etiquetas))
{
if (string.IsNullOrEmpty(newName))
{
// Si el nuevo nombre está vacío, removemos la entrada personalizada
imageData.CustomName = string.Empty;
if (string.IsNullOrEmpty(imageData.CustomName) && imageData.Tags.Count == 0)
{
_imageDataDictionary.Remove(imageName);
}
}
else
{
imageData.CustomName = newName;
}
// Forzar actualización del UI usando CollectionViewSource
var collectionView = System.Windows.Data.CollectionViewSource.GetDefaultView(ListaImagenes);
collectionView?.Refresh();
HasUnsavedChanges = true;
_imageDataDictionary.Remove(imageName);
}
// Forzar actualización del UI usando CollectionViewSource
var collectionView = System.Windows.Data.CollectionViewSource.GetDefaultView(ListaImagenes);
collectionView?.Refresh();
HasUnsavedChanges = true;
}
}

View File

@ -99,7 +99,7 @@
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Renombrar" Command="{Binding RenameImageCommand}" CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
<MenuItem Header="Propiedades" Command="{Binding RenameImageCommand}" CommandParameter="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>

View File

@ -1,6 +1,9 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using CtrEditor.ObjetosSim;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
using System.Linq;
namespace CtrEditor.Models
{
@ -8,9 +11,11 @@ namespace CtrEditor.Models
{
private string _customName;
private List<string> _tags;
private string _etiquetas;
public string FileName { get; set; }
[DisplayName("Nombre personalizado")]
public string CustomName
{
get => _customName;
@ -21,13 +26,59 @@ namespace CtrEditor.Models
}
}
[Browsable(false)]
public List<string> Tags
{
get => _tags ?? new List<string>();
set
{
_tags = value;
_etiquetas = string.Join(" ", value.Select(tag => tag.StartsWith("#") ? tag : "#" + tag));
OnPropertyChanged();
OnPropertyChanged(nameof(Etiquetas));
}
}
[DisplayName("Etiquetas")]
[property: Editor(typeof(TagPropertyEditor), typeof(TagPropertyEditor))]
public string Etiquetas
{
get => _etiquetas ?? string.Empty;
set
{
_etiquetas = value ?? string.Empty;
// Convertir string de etiquetas a List<string>
if (string.IsNullOrWhiteSpace(_etiquetas))
{
_tags = new List<string>();
}
else
{
_tags = _etiquetas.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(tag => tag.StartsWith("#") ? tag.Substring(1) : tag)
.Where(tag => !string.IsNullOrWhiteSpace(tag))
.ToList();
}
OnPropertyChanged();
OnPropertyChanged(nameof(Tags));
}
}
/// <summary>
/// Lista de etiquetas sin el prefijo #, compatible con osBase
/// </summary>
[Browsable(false)]
public List<string> ListaEtiquetas
{
get
{
if (string.IsNullOrWhiteSpace(Etiquetas))
return new List<string>();
return Etiquetas.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Select(tag => tag.StartsWith("#") ? tag.Substring(1) : tag)
.Where(tag => !string.IsNullOrWhiteSpace(tag))
.ToList();
}
}
@ -38,6 +89,7 @@ namespace CtrEditor.Models
FileName = string.Empty;
_customName = string.Empty;
_tags = new List<string>();
_etiquetas = string.Empty;
}
public ImageData(string fileName, string customName = null, List<string> tags = null)
@ -45,6 +97,7 @@ namespace CtrEditor.Models
FileName = fileName;
_customName = customName ?? string.Empty;
_tags = tags ?? new List<string>();
_etiquetas = string.Join(" ", _tags.Select(tag => tag.StartsWith("#") ? tag : "#" + tag));
}
public event PropertyChangedEventHandler PropertyChanged;

View File

@ -5,6 +5,7 @@ using System.Windows.Data;
using CtrEditor.PopUps;
using Xceed.Wpf.Toolkit.PropertyGrid;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
using CtrEditor.Models;
namespace CtrEditor.ObjetosSim
{
@ -50,18 +51,18 @@ namespace CtrEditor.ObjetosSim
{
try
{
// Obtener el objeto que se está editando
if (propertyItem.Instance is osBase osObject)
{
// Obtener el MainWindow para acceder a todos los objetos
var mainWindow = Application.Current.Windows
.OfType<MainWindow>()
.FirstOrDefault();
// Obtener el MainWindow para acceder a todos los objetos
var mainWindow = Application.Current.Windows
.OfType<MainWindow>()
.FirstOrDefault();
if (mainWindow?.DataContext is MainViewModel mainViewModel)
if (mainWindow?.DataContext is MainViewModel mainViewModel)
{
// Determinar si el objeto es osBase o ImageData
if (propertyItem.Instance is osBase osObject)
{
// Abrir el editor de etiquetas
var tagEditor = new TagEditorWindow(osObject, mainViewModel.ObjetosSimulables);
// Abrir el editor de etiquetas para osBase
var tagEditor = new TagEditorWindow(osObject, mainViewModel.ObjetosSimulables, mainViewModel._imageDataDictionary);
tagEditor.Owner = mainWindow;
if (tagEditor.ShowDialog() == true)
@ -71,6 +72,22 @@ namespace CtrEditor.ObjetosSim
textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateTarget();
}
}
else if (propertyItem.Instance is ImageData imageData)
{
// Para ImageData, crear un osBase temporal para usar el editor
var tempOsBase = new osTextPlate();
tempOsBase.Etiquetas = imageData.Etiquetas;
var tagEditor = new TagEditorWindow(tempOsBase, mainViewModel.ObjetosSimulables, mainViewModel._imageDataDictionary);
tagEditor.Owner = mainWindow;
if (tagEditor.ShowDialog() == true)
{
// Actualizar ImageData con las nuevas etiquetas
imageData.Etiquetas = tempOsBase.Etiquetas;
textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateTarget();
}
}
}
}
catch (Exception ex)

View File

@ -1,11 +1,11 @@
<Window x:Class="CtrEditor.PopUps.RenameImageWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Renombrar Imagen" Height="200" Width="400"
WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="Editar Información de Imagen" Height="400" Width="500"
WindowStartupLocation="CenterOwner" ResizeMode="CanResize">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
@ -13,12 +13,43 @@
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Archivo original:" FontWeight="Bold" Margin="0,0,0,5"/>
<TextBlock Grid.Row="1" x:Name="OriginalNameTextBlock" Margin="0,0,0,10" Foreground="Gray"/>
<TextBlock Grid.Row="1" x:Name="OriginalNameTextBlock" Margin="0,0,0,15" Foreground="Gray"/>
<TextBlock Grid.Row="2" Text="Nombre personalizado:" FontWeight="Bold" Margin="0,0,0,5"/>
<TextBox Grid.Row="3" x:Name="NewNameTextBox" Margin="0,0,0,15" VerticalAlignment="Top"/>
<GroupBox Grid.Row="2" Header="Propiedades de la Imagen" Margin="0,0,0,15">
<xctk:PropertyGrid x:Name="PropertyGridControl"
ShowSortOptions="False"
ShowSearchBox="False"
ShowSummary="True"
ShowAdvancedOptions="False"
ShowTitle="False"
Margin="5">
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorTemplateDefinition TargetProperties="Etiquetas">
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Stretch"/>
<Button Grid.Column="1"
Content="..."
Width="25"
Margin="2,0,0,0"
ToolTip="Abrir editor de etiquetas"
Click="TagEditorButton_Click"/>
</Grid>
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
</xctk:PropertyGrid.EditorDefinitions>
</xctk:PropertyGrid>
</GroupBox>
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="OkButton" Content="Aceptar" Width="80" Margin="0,0,10,0" IsDefault="True" Click="OkButton_Click"/>
<Button x:Name="CancelButton" Content="Cancelar" Width="80" IsCancel="True" Click="CancelButton_Click"/>
</StackPanel>

View File

@ -1,24 +1,72 @@
using System.Windows;
using CtrEditor.Models;
using CtrEditor.ObjetosSim;
using Xceed.Wpf.Toolkit.PropertyGrid;
namespace CtrEditor.PopUps
{
public partial class RenameImageWindow : Window
{
public string? NewImageName { get; private set; }
public ImageData ImageData { get; private set; }
public bool IsOkClicked { get; private set; }
public RenameImageWindow(string originalName, string currentCustomName = null)
public RenameImageWindow(string originalName, ImageData imageData = null)
{
InitializeComponent();
OriginalNameTextBlock.Text = originalName;
NewNameTextBox.Text = currentCustomName ?? string.Empty;
NewNameTextBox.SelectAll();
NewNameTextBox.Focus();
// Crear o usar ImageData existente
ImageData = imageData ?? new ImageData
{
FileName = originalName,
CustomName = string.Empty,
Etiquetas = string.Empty
};
// Configurar PropertyGrid
PropertyGridControl.SelectedObject = ImageData;
Focus();
}
private void TagEditorButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Obtener el MainWindow para acceder a todos los objetos
var mainWindow = Application.Current.Windows
.OfType<MainWindow>()
.FirstOrDefault();
if (mainWindow?.DataContext is MainViewModel mainViewModel)
{
// Para ImageData, crear un osBase temporal para usar el editor
var tempOsBase = new osTextPlate();
tempOsBase.Etiquetas = ImageData.Etiquetas;
var tagEditor = new TagEditorWindow(tempOsBase, mainViewModel.ObjetosSimulables, mainViewModel._imageDataDictionary);
tagEditor.Owner = this;
if (tagEditor.ShowDialog() == true)
{
// Actualizar ImageData con las nuevas etiquetas
ImageData.Etiquetas = tempOsBase.Etiquetas;
// Forzar actualización del PropertyGrid
PropertyGridControl.Update();
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error al abrir el editor de etiquetas: {ex.Message}",
"Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
NewImageName = NewNameTextBox.Text?.Trim();
IsOkClicked = true;
DialogResult = true;
Close();

View File

@ -5,6 +5,7 @@ using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CtrEditor.ObjetosSim;
using CtrEditor.Models;
namespace CtrEditor.PopUps
{
@ -13,10 +14,10 @@ namespace CtrEditor.PopUps
/// </summary>
public partial class TagEditorWindow : Window
{
public TagEditorWindow(osBase objeto, IEnumerable<osBase> todosLosObjetos)
public TagEditorWindow(osBase objeto, IEnumerable<osBase> todosLosObjetos, Dictionary<string, ImageData> imageDataDictionary = null)
{
InitializeComponent();
DataContext = new TagEditorViewModel(objeto, todosLosObjetos, this);
DataContext = new TagEditorViewModel(objeto, todosLosObjetos, this, imageDataDictionary);
}
private void TxtNuevaEtiqueta_KeyDown(object sender, KeyEventArgs e)
@ -46,6 +47,7 @@ namespace CtrEditor.PopUps
{
private readonly osBase _objeto;
private readonly IEnumerable<osBase> _todosLosObjetos;
private readonly Dictionary<string, ImageData> _imageDataDictionary;
private readonly TagEditorWindow _window;
private readonly List<string> _etiquetasOriginales;
@ -64,10 +66,11 @@ namespace CtrEditor.PopUps
public ICommand AplicarCommand { get; }
public ICommand CancelarCommand { get; }
public TagEditorViewModel(osBase objeto, IEnumerable<osBase> todosLosObjetos, TagEditorWindow window)
public TagEditorViewModel(osBase objeto, IEnumerable<osBase> todosLosObjetos, TagEditorWindow window, Dictionary<string, ImageData> imageDataDictionary = null)
{
_objeto = objeto;
_todosLosObjetos = todosLosObjetos;
_imageDataDictionary = imageDataDictionary;
_window = window;
// Guardar las etiquetas originales para poder cancelar
@ -111,9 +114,22 @@ namespace CtrEditor.PopUps
var todasLasEtiquetas = _todosLosObjetos
.SelectMany(obj => obj.ListaEtiquetas)
.Distinct()
.OrderBy(tag => tag)
.ToList();
// Agregar etiquetas de las imágenes si está disponible el diccionario
if (_imageDataDictionary != null)
{
var etiquetasImagenes = _imageDataDictionary.Values
.SelectMany(imageData => imageData.ListaEtiquetas)
.Distinct();
todasLasEtiquetas.AddRange(etiquetasImagenes);
todasLasEtiquetas = todasLasEtiquetas.Distinct().ToList();
}
// Ordenar todas las etiquetas
todasLasEtiquetas = todasLasEtiquetas.OrderBy(tag => tag).ToList();
// Mostrar solo las que no están en el objeto actual
var etiquetasObjetoActual = _objeto.ListaEtiquetas;
foreach (var tag in todasLasEtiquetas.Except(etiquetasObjetoActual))