Agregada funcion de analizar la matriz de exportacion de tags. Creada un submenu para cargar los ultimos directorios ustilizados. Cambiado intercambio de datos para los Motores simulados a DINT

This commit is contained in:
Miguel 2025-02-14 14:04:29 +01:00
parent dc164e96ef
commit 3a2e87cd75
8 changed files with 663 additions and 17 deletions

View File

@ -79,6 +79,7 @@ namespace CtrEditor
public ICommand TBAssingPagesCommand { get; }
public ICommand TBMultiPageExtractTagsCommand { get; }
public ICommand TBMultiPageAnalizeCommand { get; }
public ICommand TBAnalyzeMatrixCommand { get; }
// Evento que se dispara cuando se selecciona una nueva imagen
@ -108,6 +109,11 @@ namespace CtrEditor
[ObservableProperty]
private bool hasUnsavedChanges;
[ObservableProperty]
private ObservableCollection<string> recentDirectories;
public ICommand OpenRecentDirectoryCommand { get; private set; }
partial void OnIsSimulationRunningChanged(bool value)
{
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado
@ -148,6 +154,8 @@ namespace CtrEditor
OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad
OnPropertyChanged(nameof(ListaImagenes)); // Notificar que la lista de imágenes ha cambiado
AddToRecentDirectories(value);
}
}
}
@ -305,6 +313,7 @@ namespace CtrEditor
TBAssingPagesCommand = new RelayCommand(AssingPagesCommand);
TBMultiPageExtractTagsCommand = new RelayCommand(MultiPageExtractTagsCommand);
TBMultiPageAnalizeCommand = new RelayCommand(MultiPageAnalizeCommand);
TBAnalyzeMatrixCommand = new RelayCommand(AnalyzeMatrixCommand);
stopwatch_Sim = new Stopwatch();
stopwatch_Sim.Start();
@ -314,6 +323,9 @@ namespace CtrEditor
if (e.Action != NotifyCollectionChangedAction.Move)
HasUnsavedChanges = true;
};
recentDirectories = new ObservableCollection<string>(EstadoPersistente.Instance.RecentDirectories);
OpenRecentDirectoryCommand = new RelayCommand<string>(OpenRecentDirectory);
}
private void OsListFilter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@ -873,6 +885,43 @@ namespace CtrEditor
}
}
private void OpenRecentDirectory(string path)
{
if (Directory.Exists(path))
{
directorioTrabajo = path;
}
else
{
MessageBox.Show($"Directory not found: {path}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
RecentDirectories.Remove(path);
UpdateRecentDirectories();
}
}
private void UpdateRecentDirectories()
{
EstadoPersistente.Instance.RecentDirectories = RecentDirectories.ToList();
EstadoPersistente.Instance.GuardarEstado();
}
private void AddToRecentDirectories(string path)
{
// Remove the path if it already exists
RecentDirectories.Remove(path);
// Add the new path at the beginning
RecentDirectories.Insert(0, path);
// Keep only the last 10 entries
while (RecentDirectories.Count > 10)
{
RecentDirectories.RemoveAt(RecentDirectories.Count - 1);
}
UpdateRecentDirectories();
}
//
// Lista de osBase
//
@ -1051,6 +1100,15 @@ namespace CtrEditor
}
Application.Current.Shutdown();
}
private void AnalyzeMatrixCommand()
{
var matrixPreviewWindow = new MatrixPreviewWindow();
var matrixPreviewViewModel = new MatrixPreviewViewModel();
matrixPreviewViewModel.Initialize(this, matrixPreviewWindow);
matrixPreviewWindow.DataContext = matrixPreviewViewModel;
matrixPreviewWindow.ShowDialog();
}
}
public class SimulationData
{

View File

@ -41,6 +41,14 @@
<Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
<MenuItem Header="Projecto">
<MenuItem Header="Abrir Directorio de trabajo" Command="{Binding OpenWorkDirectoryCommand}" />
<MenuItem Header="Ultimos Directorios Utilizados" ItemsSource="{Binding RecentDirectories}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}" Command="{Binding DataContext.OpenRecentDirectoryCommand, RelativeSource={RelativeSource AncestorType=MenuItem, AncestorLevel=2}}"
CommandParameter="{Binding}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Iniciar Simulacion" Command="{Binding StartSimulationCommand}" />
<MenuItem Header="Detenet Simulacion" Command="{Binding StopSimulationCommand}" />
<MenuItem Header="Debug Window" Command="{Binding DebugWindowCommand}" />
@ -132,7 +140,7 @@
<Image Source="Icons/extract.png" Width="24" Height="24" />
<TextBlock Text="Multi Page Extract" />
</StackPanel>
</Button>a
</Button>
<Button Command="{Binding TBMultiPageAnalizeCommand}"
ToolTip="Analyze Tags in multiple pages.">
<StackPanel>
@ -140,6 +148,12 @@
<TextBlock Text="Multi Page Analyze" />
</StackPanel>
</Button>
<Button Command="{Binding TBAnalyzeMatrixCommand}" ToolTip="Analyze Export Matrix">
<StackPanel>
<Image Source="Icons/analyze.png" Width="24" Height="24" />
<TextBlock Text="Analyze Matrix" />
</StackPanel>
</Button>
</ToolBar>
</ToolBarTray>

View File

@ -1,5 +1,4 @@

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.FuncionesBase;
using LibS7Adv;
using Newtonsoft.Json;
@ -46,7 +45,7 @@ namespace CtrEditor.ObjetosSim
}
[ObservableProperty]
public float refresh_Time_ms;
public float refresh_Time_ms;
[ObservableProperty]
public float proporcional_Speed;
@ -208,17 +207,21 @@ namespace CtrEditor.ObjetosSim
if (DB_Motor == 0)
return;
// Read ControlWord in one operation
int controlWord = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord") ?? 0;
var control = VMMotorBitPacker.UnpackControlWord(controlWord);
OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].OUT.Run");
OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].OUT.\"Reversal Direction\"");
OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{DB_Motor}].OUT.OUT_VFD_REQ_Speed_Hz");
// Update local state from ControlWord
OUT_Run = control.run;
OUT_Stop = control.stop;
OUT_Reversal = control.reversal;
OUT_OUT_VFD_REQ_Speed_Hz = control.reqSpeedHz;
// Update motor state based on enable status
if (Data.Encendido)
{
_STATUS_VFD_Ready = true;
Motor_Running = true;
Motor_Running = OUT_Run && !OUT_Stop;
STATUS_VFD_Trip = false;
STATUS_VFD_Warning = false;
STATUS_VFD_Coasting = false;
@ -235,14 +238,18 @@ namespace CtrEditor.ObjetosSim
if (Data.VFD_Trip_NC)
STATUS_VFD_Trip = !STATUS_VFD_Trip;
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].STATUS_VFD_Ready", _STATUS_VFD_Ready);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].Motor_Running", Motor_Running);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].STATUS_VFD_Trip", STATUS_VFD_Trip);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].STATUS_VFD_Warning", STATUS_VFD_Warning);
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{DB_Motor}].STATUS_VFD_Coasting", STATUS_VFD_Coasting);
plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{DB_Motor}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz);
// Pack all status bits and speed into StatusWord
int statusWord = VMMotorBitPacker.PackStatusWord(
_STATUS_VFD_Ready,
Motor_Running,
STATUS_VFD_Trip,
STATUS_VFD_Warning,
STATUS_VFD_Coasting,
(short)STATUS_VFD_ACT_Speed_Hz
);
// Write StatusWord in one operation
plc.EscribirTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].StatusWord", statusWord);
}
private float CalcSpeedRamp(float max_Speed_for_Ramp, float TiempoRampa, float actual, float expected, int TotalMilliseconds)

View File

@ -0,0 +1,70 @@
namespace CtrEditor.ObjetosSim
{
public static class VMMotorBitPacker
{
// Bit positions for StatusWord (bits 16-31)
private const int STATUS_VFD_READY_BIT = 16;
private const int MOTOR_RUNNING_BIT = 17;
private const int STATUS_VFD_TRIP_BIT = 18;
private const int STATUS_VFD_WARNING_BIT = 19;
private const int STATUS_VFD_COASTING_BIT = 20;
// Bits 21-31 reserved for future use
// Bits 0-15 used for STATUS_VFD_ACT_Speed_Hz (16 bits)
// Bit positions for ControlWord (bits 16-31)
private const int OUT_RUN_BIT = 16;
private const int OUT_STOP_BIT = 17;
private const int OUT_RESET_ALARM_BIT = 18;
private const int OUT_REVERSAL_BIT = 19;
// Bits 20-31 reserved for future use
// Bits 0-15 used for OUT_VFD_REQ_Speed_Hz (16 bits)
public static int PackStatusWord(bool vfdReady, bool motorRunning, bool vfdTrip,
bool vfdWarning, bool vfdCoasting, short actSpeedHz)
{
int result = actSpeedHz & 0xFFFF; // Speed in lower 16 bits
result |= (vfdReady ? 1 : 0) << STATUS_VFD_READY_BIT;
result |= (motorRunning ? 1 : 0) << MOTOR_RUNNING_BIT;
result |= (vfdTrip ? 1 : 0) << STATUS_VFD_TRIP_BIT;
result |= (vfdWarning ? 1 : 0) << STATUS_VFD_WARNING_BIT;
result |= (vfdCoasting ? 1 : 0) << STATUS_VFD_COASTING_BIT;
return result;
}
public static int PackControlWord(bool run, bool stop, bool resetAlarm,
bool reversal, short reqSpeedHz)
{
int result = reqSpeedHz & 0xFFFF; // Speed in lower 16 bits
result |= (run ? 1 : 0) << OUT_RUN_BIT;
result |= (stop ? 1 : 0) << OUT_STOP_BIT;
result |= (resetAlarm ? 1 : 0) << OUT_RESET_ALARM_BIT;
result |= (reversal ? 1 : 0) << OUT_REVERSAL_BIT;
return result;
}
public static (bool vfdReady, bool motorRunning, bool vfdTrip, bool vfdWarning,
bool vfdCoasting, short actSpeedHz) UnpackStatusWord(int statusWord)
{
return (
((statusWord >> STATUS_VFD_READY_BIT) & 1) == 1,
((statusWord >> MOTOR_RUNNING_BIT) & 1) == 1,
((statusWord >> STATUS_VFD_TRIP_BIT) & 1) == 1,
((statusWord >> STATUS_VFD_WARNING_BIT) & 1) == 1,
((statusWord >> STATUS_VFD_COASTING_BIT) & 1) == 1,
(short)(statusWord & 0xFFFF)
);
}
public static (bool run, bool stop, bool resetAlarm, bool reversal, short reqSpeedHz)
UnpackControlWord(int controlWord)
{
return (
((controlWord >> OUT_RUN_BIT) & 1) == 1,
((controlWord >> OUT_STOP_BIT) & 1) == 1,
((controlWord >> OUT_RESET_ALARM_BIT) & 1) == 1,
((controlWord >> OUT_REVERSAL_BIT) & 1) == 1,
(short)(controlWord & 0xFFFF)
);
}
}
}

View File

@ -0,0 +1,85 @@
<Window x:Class="CtrEditor.PopUps.MatrixPreviewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Export Matrix Preview" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Matrix Preview -->
<DataGrid x:Name="MatrixPreview"
Grid.Row="0"
ItemsSource="{Binding MatrixRows}"
AutoGenerateColumns="False"
CanUserReorderColumns="True"
CanUserAddRows="False"
HeadersVisibility="Column"
Background="White"
GridLinesVisibility="All"
Margin="5"
ColumnReordered="DataGrid_ColumnReordered">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="LightGray"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="5"/>
</Style>
</DataGrid.Resources>
</DataGrid>
<!-- GridSplitter between tables -->
<GridSplitter Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch"
Background="LightGray"
ResizeDirection="Rows"/>
<!-- Column Details -->
<DataGrid Grid.Row="2"
ItemsSource="{Binding MatrixItems}"
AutoGenerateColumns="False"
CanUserAddRows="False"
Margin="5">
<DataGrid.Columns>
<DataGridTextColumn Header="Column Number"
Binding="{Binding ColumnNumber, UpdateSourceTrigger=PropertyChanged}"
Width="100"/>
<DataGridTextColumn Header="Column Name"
Binding="{Binding ColumnName, UpdateSourceTrigger=PropertyChanged}"
Width="150"/>
<DataGridTextColumn Header="Tag Name"
Binding="{Binding TagName}"
Width="150"
IsReadOnly="True"/>
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
Width="100"
IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
<!-- Bottom Panel with Buttons -->
<StackPanel Grid.Row="3"
Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="5"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<Button Content="Regenerate Matrix"
Command="{Binding RegenerateMatrixCommand}"
Margin="5"
Padding="10,5"/>
<Button Content="Apply Changes"
Command="{Binding ApplyChangesCommand}"
Margin="5"
Padding="10,5"/>
<Button Content="Close"
Command="{Binding CloseCommand}"
Margin="5"
Padding="10,5"/>
</StackPanel>
</Grid>
</Window>

View File

@ -0,0 +1,46 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Linq;
using System.Diagnostics;
namespace CtrEditor.PopUps
{
public partial class MatrixPreviewWindow : Window
{
public MatrixPreviewWindow()
{
InitializeComponent();
}
private void DataGrid_ColumnReordered(object sender, DataGridColumnEventArgs e)
{
if (DataContext is MatrixPreviewViewModel viewModel)
{
// Obtener el nuevo orden basado en DisplayIndex
var orderedColumns = MatrixPreview.Columns
.OrderBy(c => c.DisplayIndex)
.ToList();
// Actualizar los números de columna basado en DisplayIndex
for (int i = 0; i < orderedColumns.Count; i++)
{
var column = orderedColumns[i];
var headerParts = column.Header?.ToString().Split(':');
if (headerParts?.Length == 2)
{
var columnName = headerParts[1];
// Actualizar todos los items que tengan el mismo nombre de columna
var itemsToUpdate = viewModel.MatrixItems.Where(x => x.ColumnName == columnName);
foreach (var item in itemsToUpdate)
{
item.ColumnNumber = i + 1;
}
// Actualizar el header con el nuevo número
column.Header = $"{i + 1}:{columnName}";
}
}
}
}
}
}

View File

@ -0,0 +1,363 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CtrEditor.ObjetosSim;
using CtrEditor.ObjetosSim.Extraccion_Datos;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Linq;
namespace CtrEditor.PopUps
{
public class MatrixItem : ObservableObject
{
public string TagName { get; set; }
private string columnName;
public string ColumnName
{
get => columnName;
set => SetProperty(ref columnName, value);
}
private int columnNumber;
public int ColumnNumber
{
get => columnNumber;
set => SetProperty(ref columnNumber, value);
}
public string Value { get; set; }
public string Type { get; set; }
public bool IsCloned { get; set; }
public osBase SourceObject { get; set; }
}
public partial class MatrixPreviewViewModel : ObservableObject
{
private Window _window;
private MainViewModel _mainViewModel;
private DataGrid _dataGrid;
[ObservableProperty]
private ObservableCollection<MatrixItem> matrixItems;
[ObservableProperty]
private ObservableCollection<Dictionary<string, string>> matrixRows;
[ObservableProperty]
private GridLength detailsHeight = new GridLength(150);
[ObservableProperty]
private double detailsHeightValue = 150;
partial void OnDetailsHeightValueChanged(double value)
{
DetailsHeight = new GridLength(value);
}
public void Initialize(MainViewModel mainViewModel, Window window)
{
_mainViewModel = mainViewModel;
_window = window;
_dataGrid = (_window as MatrixPreviewWindow)?.MatrixPreview;
MatrixItems = new ObservableCollection<MatrixItem>();
MatrixRows = new ObservableCollection<Dictionary<string, string>>();
AnalyzeMatrix();
}
private void UpdateMatrixPreview()
{
if (_dataGrid == null) return;
if (MatrixRows == null) MatrixRows = new ObservableCollection<Dictionary<string, string>>();
MatrixRows.Clear();
_dataGrid.Columns.Clear();
if (!MatrixItems.Any()) return;
// Ordenar items por número de columna
var orderedItems = MatrixItems
.GroupBy(x => x.ColumnNumber)
.OrderBy(g => g.Key)
.Select(g => g.First())
.ToList();
// Crear columnas
foreach (var item in orderedItems)
{
var column = new DataGridTextColumn
{
Header = $"{item.ColumnNumber}:{item.ColumnName}",
Binding = new Binding($"[{item.ColumnNumber}]"),
Width = DataGridLength.Auto
};
_dataGrid.Columns.Add(column);
}
// Calcular número de filas necesarias
int maxRows = 1;
var clonedItems = MatrixItems.Where(x => x.IsCloned).ToList();
if (clonedItems.Any())
{
maxRows = clonedItems.Max(x => x.SourceObject is osExtraccionTag tag ? tag.Copy_Number : 0) + 1;
}
// Crear filas con valores
for (int row = 0; row < maxRows; row++)
{
var rowData = new Dictionary<string, string>();
// Agregar valores fijos (no clonados) en todas las filas
foreach (var item in MatrixItems.Where(x => !x.IsCloned))
{
if (item.ColumnNumber > 0)
{
rowData[item.ColumnNumber.ToString()] = item.Value ?? string.Empty;
}
}
// Agregar valores clonados solo en su fila correspondiente
foreach (var item in MatrixItems.Where(x => x.IsCloned))
{
if (item.ColumnNumber > 0 && item.SourceObject is osExtraccionTag tag && tag.Copy_Number == row)
{
rowData[item.ColumnNumber.ToString()] = item.Value ?? string.Empty;
}
}
MatrixRows.Add(rowData);
}
}
private void UpdateColumnHeaders()
{
if (_dataGrid == null) return;
foreach (var col in _dataGrid.Columns.Cast<DataGridColumn>())
{
if (col is DataGridTextColumn textCol)
{
var item = MatrixItems.FirstOrDefault(x => x.ColumnName == (textCol.Header?.ToString() ?? "").Split(':').Last());
if (item != null)
{
textCol.Header = $"{item.ColumnNumber}:{item.ColumnName}";
}
}
}
}
private void AnalyzeMatrix()
{
var osBuscarCoincidencias_List = _mainViewModel.ObjetosSimulables
.OfType<osBuscarCoincidencias>()
.Where(tag => tag.Show_On_This_Page)
.ToList();
var osExtraccionTagBaseGrouped_List = _mainViewModel.ObjetosSimulables
.OfType<osExtraccionTag>()
.Where(tag => tag.Show_On_This_Page && !tag.Cloned && tag.Id_Search_Templates != null && tag.Id_Search_Templates != "")
.ToList();
var osExtraccionTagBaseFix_List = _mainViewModel.ObjetosSimulables
.OfType<osExtraccionTag>()
.Where(tag => tag.Show_On_This_Page && !tag.Cloned && (tag.Id_Search_Templates == null || tag.Id_Search_Templates == ""))
.ToList();
var osExtraccionTagCloned_List = _mainViewModel.ObjetosSimulables
.OfType<osExtraccionTag>()
.Where(tag => tag.Show_On_This_Page && tag.Cloned)
.ToList();
// Add fixed tags
foreach (var tag in osExtraccionTagBaseFix_List)
{
tag.CaptureImageAreaAndDoOCR();
MatrixItems.Add(new MatrixItem
{
TagName = tag.Nombre,
ColumnName = tag.Collumn_name,
ColumnNumber = tag.Collumn_number,
Value = tag.Tag_extract,
Type = "Fixed",
IsCloned = false,
SourceObject = tag
});
}
// Add grouped tags
foreach (var tag in osExtraccionTagBaseGrouped_List)
{
tag.CaptureImageAreaAndDoOCR();
MatrixItems.Add(new MatrixItem
{
TagName = tag.Nombre,
ColumnName = tag.Collumn_name,
ColumnNumber = tag.Collumn_number,
Value = tag.Tag_extract,
Type = $"Grouped ({tag.Id_Search_Templates})",
IsCloned = false,
SourceObject = tag
});
}
// Add cloned tags
foreach (var tag in osExtraccionTagCloned_List)
{
tag.CaptureImageAreaAndDoOCR();
MatrixItems.Add(new MatrixItem
{
TagName = tag.Nombre,
ColumnName = tag.Collumn_name,
ColumnNumber = tag.Collumn_number,
Value = tag.Tag_extract,
Type = "Cloned",
IsCloned = true,
SourceObject = tag
});
}
// Ordenar los items por número de columna
var items = MatrixItems.OrderBy(x => x.ColumnNumber).ToList();
MatrixItems.Clear();
foreach (var item in items)
{
MatrixItems.Add(item);
}
ResolveColumnConflicts(); // Analizar y resolver conflictos al cargar
UpdateMatrixPreview();
}
partial void OnMatrixItemsChanged(ObservableCollection<MatrixItem> value)
{
if (value != null)
{
foreach (var item in value)
{
item.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(MatrixItem.ColumnNumber) ||
e.PropertyName == nameof(MatrixItem.ColumnName))
{
UpdateColumnHeaders();
}
};
}
}
UpdateMatrixPreview();
}
[RelayCommand]
private void ApplyChanges()
{
// Resolver solo los conflictos reales, mantener el orden existente
var conflicts = MatrixItems
.GroupBy(x => x.ColumnNumber)
.Where(g => g.Select(x => x.ColumnName).Distinct().Count() > 1)
.Any();
if (conflicts)
{
ResolveColumnConflicts();
}
// Validar números de columna
var columnNumbers = MatrixItems.Select(x => x.ColumnNumber).OrderBy(x => x).ToList();
for (int i = 0; i < columnNumbers.Count; i++)
{
if (columnNumbers[i] <= 0)
{
MessageBox.Show("Column numbers must be greater than 0", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
// Aplicar cambios a los objetos
foreach (var item in MatrixItems)
{
if (item.SourceObject is osExtraccionTag tag)
{
tag.Collumn_name = item.ColumnName;
tag.Collumn_number = item.ColumnNumber;
}
}
_mainViewModel.HasUnsavedChanges = true;
_window.Close();
}
[RelayCommand]
private void Close()
{
_window.Close();
}
[RelayCommand]
private void RegenerateMatrix()
{
ResolveColumnConflicts();
UpdateMatrixPreview();
}
private void ResolveColumnConflicts()
{
// Paso 1: Mantener el orden actual y resolver solo los conflictos reales
var columnGroups = MatrixItems
.GroupBy(x => x.ColumnNumber)
.Where(g => g.Select(x => x.ColumnName).Distinct().Count() > 1)
.ToList();
foreach (var group in columnGroups)
{
var nameGroups = group
.GroupBy(x => x.ColumnName)
.OrderByDescending(g => g.Count())
.ToList();
// El grupo más grande mantiene su número
var largestGroup = nameGroups.First();
// Solo reasignar números para grupos que tengan conflicto
for (int i = 1; i < nameGroups.Count; i++)
{
var newColumnNumber = GetNextAvailableColumnNumber();
foreach (var item in nameGroups[i])
{
item.ColumnNumber = newColumnNumber;
}
}
}
// Paso 2: Asegurarse de que los números son consecutivos sin alterar el orden relativo
var orderedItems = MatrixItems
.OrderBy(x => x.ColumnNumber)
.GroupBy(x => x.ColumnName)
.ToList();
int currentNumber = 1;
foreach (var group in orderedItems)
{
foreach (var item in group)
{
item.ColumnNumber = currentNumber;
}
currentNumber++;
}
}
private int GetNextAvailableColumnNumber()
{
var usedNumbers = MatrixItems.Select(x => x.ColumnNumber).Distinct().OrderBy(x => x).ToList();
int nextNumber = 1;
foreach (var number in usedNumbers)
{
if (number > nextNumber)
return nextNumber;
nextNumber = number + 1;
}
return nextNumber;
}
}
}

View File

@ -26,6 +26,8 @@ namespace CtrEditor
public ObjetosSimulablesFilterTypes osListFilter;
public List<string> RecentDirectories { get; set; } = new List<string>();
// Propiedad pública con get y set para controlar el acceso a _strDirectorioTrabajo
public string directorio
{
@ -55,6 +57,7 @@ namespace CtrEditor
private EstadoPersistente Inizializar()
{
_strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
RecentDirectories = new List<string>();
return this;
}