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:
parent
dc164e96ef
commit
3a2e87cd75
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue