Erweiterung der Platzhalter- und Speicherverwaltung
Die `GridControl`-Klasse wurde erweitert, um dynamische Platzhalterverarbeitung zu unterstützen. Dies umfasst die Einführung eines neuen Feldes `_ParentControl`, die Anpassung des Konstruktors und die Erweiterung der Methode `ResolveSqlTemplate`. Neue Ereignisse wie `HiddenEditor` wurden hinzugefügt, um Speicherlecks zu vermeiden, und die `ShowingEditor`-Logik wurde verbessert, um alte Editoren korrekt zu entfernen und zu entsorgen. Dynamische Editor-Spalten werden nun gecacht, und Debugging-Informationen wurden in mehreren Methoden ergänzt. Formulare wie `frmColumn_Detail`, `frmFormDesigner`, `frmMassValidator` und `frmValidator` wurden angepasst, um das neue Verhalten zu unterstützen. Verbesserte Fehlerbehandlung und Protokollierung erhöhen die Stabilität und Nachverfolgbarkeit.
This commit is contained in:
@@ -544,8 +544,9 @@ Public Class ClassControlCreator
|
||||
Return oControl
|
||||
End Function
|
||||
|
||||
Public Function CreateExistingGridControl(row As DataRow, DT_MY_COLUMNS As DataTable, designMode As Boolean, pcurrencySymbol As String) As GridControl
|
||||
Dim oGridControlCreator = New ControlCreator.GridControl(LogConfig, GridTables, pcurrencySymbol)
|
||||
Public Function CreateExistingGridControl(row As DataRow, DT_MY_COLUMNS As DataTable, designMode As Boolean,
|
||||
pcurrencySymbol As String, pParentControl As Control) As GridControl
|
||||
Dim oGridControlCreator = New ControlCreator.GridControl(LogConfig, GridTables, pcurrencySymbol, pParentControl)
|
||||
Dim oControl As GridControl = CreateBaseControl(New GridControl(), row, designMode)
|
||||
Dim oControlId = DirectCast(oControl.Tag, ControlMetadata).Guid
|
||||
Dim oView As GridView
|
||||
|
||||
@@ -22,11 +22,13 @@ Namespace ControlCreator
|
||||
Private ReadOnly _LogConfig As LogConfig
|
||||
Private ReadOnly _Logger As Logger
|
||||
Private ReadOnly _GridTables As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem))
|
||||
Private ReadOnly _ParentControl As Control
|
||||
|
||||
Private newRowModified As Boolean
|
||||
Private isApplyingInheritedValue As Boolean
|
||||
Private _FormulaColumnNames As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
|
||||
Private _FormulaSqlColumns As New Dictionary(Of String, FormulaSqlDefinition)(StringComparer.OrdinalIgnoreCase)
|
||||
Private _DynamicEditorColumns As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
|
||||
|
||||
Private _isRefreshingFormula As Boolean = False ' *** NEU: Flag für Formel-Refresh ***
|
||||
Private _currencySymbol As String = "€"
|
||||
@@ -71,9 +73,9 @@ Namespace ControlCreator
|
||||
''' </summary>
|
||||
Private Function ResolveSqlTemplate(sqlTemplate As String, pView As GridView, rowHandle As Integer) As String
|
||||
Dim resolvedSql As String = sqlTemplate
|
||||
' *** SCHRITT 1: {#TBCOL#...} Platzhalter ersetzen (BESTEHENDER CODE) ***
|
||||
Dim pattern As String = "\{#TBCOL#([^}]+)\}"
|
||||
Dim matches = Regex.Matches(sqlTemplate, pattern)
|
||||
|
||||
For Each match As Match In matches
|
||||
Dim colName = match.Groups(1).Value
|
||||
Dim cellValue = pView.GetRowCellValue(rowHandle, colName)
|
||||
@@ -94,14 +96,28 @@ Namespace ControlCreator
|
||||
resolvedSql = resolvedSql.Replace(match.Value, safeValue)
|
||||
_Logger.Debug("Resolved SQL placeholder [{0}] with value [{1}] → {2}", match.Value, cellValue, safeValue)
|
||||
Next
|
||||
' *** SCHRITT 2: Weitere Patterns via clsPatterns ersetzen (NEU) ***
|
||||
If _ParentControl IsNot Nothing Then
|
||||
Try
|
||||
_Logger.Debug("Applying clsPatterns.ReplaceAllValues() to SQL: {0}", resolvedSql)
|
||||
resolvedSql = clsPatterns.ReplaceAllValues(resolvedSql, _ParentControl, True)
|
||||
_Logger.Debug("After clsPatterns: {0}", resolvedSql)
|
||||
Catch ex As Exception
|
||||
_Logger.Warn("⚠️ clsPatterns.ReplaceAllValues() failed: {0}", ex.Message)
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
Else
|
||||
_Logger.Debug("ParentControl is Nothing – skipping clsPatterns.ReplaceAllValues()")
|
||||
End If
|
||||
_Logger.Debug("Final resolved SQL: {0}", resolvedSql)
|
||||
Return resolvedSql
|
||||
End Function
|
||||
Public Sub New(pLogConfig As LogConfig, pGridTables As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem)), pCurrencySymbol As String)
|
||||
Public Sub New(pLogConfig As LogConfig, pGridTables As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem)), pCurrencySymbol As String, pParentControl As Control)
|
||||
_LogConfig = pLogConfig
|
||||
_Logger = pLogConfig.GetLogger()
|
||||
_GridTables = pGridTables
|
||||
_currencySymbol = pCurrencySymbol
|
||||
_ParentControl = pParentControl ' *** NEU ***
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' Setzt den Shared Currency-Cache zurück. Muss beim Laden eines neuen Dokuments
|
||||
@@ -676,6 +692,7 @@ Namespace ControlCreator
|
||||
' *** Formel-Spalten einmalig cachen + Validierung: Entweder EXPRESSION oder SQL, nie beides ***
|
||||
_FormulaColumnNames.Clear()
|
||||
_FormulaSqlColumns.Clear()
|
||||
_DynamicEditorColumns.Clear()
|
||||
|
||||
For Each r As DataRow In pColumnTable.Rows
|
||||
Dim oColName = r.Item("SPALTENNAME").ToString()
|
||||
@@ -709,6 +726,13 @@ Namespace ControlCreator
|
||||
_Logger.Debug("[ConfigureViewEvents] Column [{0}] registered as FORMULA_SQL column. ReferencedColumns=[{1}]",
|
||||
oColName, String.Join(", ", GetReferencedSqlColumnNames(oSql_FORMULA)))
|
||||
End If
|
||||
|
||||
' *** NEU: Dynamische Editor-Spalten cachen ***
|
||||
Dim oSqlCommand As String = r.ItemEx("SQL_COMMAND", "")
|
||||
If oSqlCommand <> "" AndAlso (ContainsTableColumnPlaceholder(oSqlCommand) OrElse clsPatterns.HasComplexPatterns(oSqlCommand)) Then
|
||||
_DynamicEditorColumns.Add(oColName)
|
||||
_Logger.Debug("[ConfigureViewEvents] Column [{0}] registered as DYNAMIC_EDITOR column (has placeholders)", oColName)
|
||||
End If
|
||||
Next
|
||||
|
||||
AddHandler pGridView.InitNewRow, Sub(sender As Object, e As InitNewRowEventArgs)
|
||||
@@ -811,6 +835,13 @@ Namespace ControlCreator
|
||||
If oColumnName <> e.Column.FieldName Then Continue For
|
||||
Dim oSqlCommand As String = oRow.ItemEx("SQL_COMMAND", "")
|
||||
Dim oConnectionId As Integer = oRow.ItemEx("CONNECTION_ID", 1)
|
||||
' *** KRITISCH: Prüfe ZUERST, ob diese Spalte #TBCOL# Platzhalter hat ***
|
||||
If oSqlCommand <> "" AndAlso (ContainsTableColumnPlaceholder(oSqlCommand) Or
|
||||
clsPatterns.HasComplexPatterns(oSqlCommand)) Then
|
||||
_Logger.Debug("[CustomRowCellEdit] Column [{0}] has placeholders – SKIPPING, editor set by ShowingEditor", oColumnName)
|
||||
' *** NICHTS TUN – ShowingEditor verwaltet den Editor ***
|
||||
Exit For
|
||||
End If
|
||||
|
||||
Dim oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, oColumnName)
|
||||
|
||||
@@ -1007,6 +1038,30 @@ Namespace ControlCreator
|
||||
If oSqlCommand <> "" AndAlso ContainsTableColumnPlaceholder(oSqlCommand) Then
|
||||
_Logger.Debug("[ShowingEditor] Column [{0}] has SQL with #TBCOL# placeholders – creating row-specific editor", oFocusedColumnName)
|
||||
|
||||
' *** KRITISCH: Alten Editor VORHER entfernen ***
|
||||
Dim oldEditor = oView.FocusedColumn.ColumnEdit
|
||||
If oldEditor IsNot Nothing Then
|
||||
_Logger.Debug("[ShowingEditor] Removing old ColumnEdit (Type=[{0}], HashCode=[{1}])",
|
||||
oldEditor.GetType().Name, oldEditor.GetHashCode())
|
||||
|
||||
' Editor von Spalte entfernen
|
||||
oView.FocusedColumn.ColumnEdit = Nothing
|
||||
|
||||
' *** NEU: Editor aus RepositoryItems entfernen, falls vorhanden ***
|
||||
If oView.GridControl.RepositoryItems.Contains(oldEditor) Then
|
||||
oView.GridControl.RepositoryItems.Remove(oldEditor)
|
||||
_Logger.Debug("[ShowingEditor] Removed old editor from RepositoryItems")
|
||||
End If
|
||||
|
||||
' *** KRITISCH: Dispose() aufrufen um Memory Leaks zu vermeiden ***
|
||||
Try
|
||||
oldEditor.Dispose()
|
||||
_Logger.Debug("[ShowingEditor] Disposed old editor")
|
||||
Catch disposeEx As Exception
|
||||
_Logger.Warn("[ShowingEditor] Could not dispose old editor: {0}", disposeEx.Message)
|
||||
End Try
|
||||
End If
|
||||
|
||||
' Platzhalter ersetzen mit aktuellen Zeilenwerten
|
||||
Dim resolvedSql As String = ResolveSqlTemplate(oSqlCommand, oView, oRowHandle)
|
||||
|
||||
@@ -1018,9 +1073,40 @@ Namespace ControlCreator
|
||||
oColumnData.ItemEx("ADVANCED_LOOKUP", False))
|
||||
|
||||
If oRowSpecificEditor IsNot Nothing Then
|
||||
' Editor temporär zur Spalte hinzufügen
|
||||
_Logger.Debug("[ShowingEditor] Created new editor (Type=[{0}], HashCode=[{1}])",
|
||||
oRowSpecificEditor.GetType().Name,
|
||||
oRowSpecificEditor.GetHashCode())
|
||||
|
||||
' *** KRITISCH: DataSource-Größe loggen für Debugging ***
|
||||
If TypeOf oRowSpecificEditor Is RepositoryItemLookupControl3 Then
|
||||
Dim lookupEditor = DirectCast(oRowSpecificEditor, RepositoryItemLookupControl3)
|
||||
If lookupEditor.DataSource IsNot Nothing AndAlso TypeOf lookupEditor.DataSource Is DataTable Then
|
||||
Dim dt = DirectCast(lookupEditor.DataSource, DataTable)
|
||||
_Logger.Debug("[ShowingEditor] LookupEditor DataSource: [{0}] rows", dt.Rows.Count)
|
||||
' Log first 3 values for verification
|
||||
For i As Integer = 0 To Math.Min(2, dt.Rows.Count - 1)
|
||||
_Logger.Debug("[ShowingEditor] Row[{0}]: [{1}]", i, dt.Rows(i)(0))
|
||||
Next
|
||||
End If
|
||||
ElseIf TypeOf oRowSpecificEditor Is RepositoryItemComboBox Then
|
||||
Dim comboEditor = DirectCast(oRowSpecificEditor, RepositoryItemComboBox)
|
||||
_Logger.Debug("[ShowingEditor] ComboBoxEditor Items: [{0}] items", comboEditor.Items.Count)
|
||||
' Log first 3 items
|
||||
For i As Integer = 0 To Math.Min(2, comboEditor.Items.Count - 1)
|
||||
_Logger.Debug("[ShowingEditor] Item[{0}]: [{1}]", i, comboEditor.Items(i))
|
||||
Next
|
||||
End If
|
||||
|
||||
' *** KRITISCH: Editor zur GridControl.RepositoryItems hinzufügen ***
|
||||
' Dies stellt sicher, dass DevExpress den Editor korrekt verwaltet
|
||||
oView.GridControl.RepositoryItems.Add(oRowSpecificEditor)
|
||||
_Logger.Debug("[ShowingEditor] Added editor to RepositoryItems (Total count: {0})",
|
||||
oView.GridControl.RepositoryItems.Count)
|
||||
|
||||
' Editor zur Spalte zuweisen
|
||||
oView.FocusedColumn.ColumnEdit = oRowSpecificEditor
|
||||
_Logger.Debug("[ShowingEditor] Row-specific editor assigned for [{0}]", oFocusedColumnName)
|
||||
|
||||
_Logger.Debug("[ShowingEditor] Row-specific editor assigned and refreshed for [{0}]", oFocusedColumnName)
|
||||
Else
|
||||
_Logger.Warn("[ShowingEditor] Failed to create row-specific editor for [{0}] – cancelling edit", oFocusedColumnName)
|
||||
e.Cancel = True
|
||||
@@ -1036,6 +1122,59 @@ Namespace ControlCreator
|
||||
oView.AddNewRow()
|
||||
End If
|
||||
Catch ex As Exception
|
||||
_Logger.Error("[ShowingEditor] Error: {0}", ex.Message)
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
' *** NEU: HiddenEditor-Event für Cleanup ***
|
||||
AddHandler pGridView.HiddenEditor,
|
||||
Sub(sender As Object, e As EventArgs)
|
||||
Try
|
||||
Dim oView As GridView = TryCast(sender, GridView)
|
||||
If oView Is Nothing OrElse oView.FocusedColumn Is Nothing Then Return
|
||||
|
||||
Dim oFocusedColumnName As String = oView.FocusedColumn.FieldName
|
||||
|
||||
' Prüfen ob diese Spalte dynamische Editoren verwendet
|
||||
Dim oColumnData As DataRow = pColumnTable.
|
||||
Select($"SPALTENNAME = '{oFocusedColumnName}'").
|
||||
FirstOrDefault()
|
||||
|
||||
If oColumnData IsNot Nothing Then
|
||||
Dim oSqlCommand As String = oColumnData.ItemEx("SQL_COMMAND", "")
|
||||
|
||||
' Wenn Spalte #TBCOL# verwendet → Editor nach Schließen entfernen
|
||||
If oSqlCommand <> "" AndAlso ContainsTableColumnPlaceholder(oSqlCommand) Then
|
||||
Dim currentEditor = oView.FocusedColumn.ColumnEdit
|
||||
|
||||
If currentEditor IsNot Nothing Then
|
||||
_Logger.Debug("[HiddenEditor] Cleaning up row-specific editor for [{0}] (HashCode=[{1}])",
|
||||
oFocusedColumnName, currentEditor.GetHashCode())
|
||||
|
||||
' Editor von Spalte entfernen
|
||||
oView.FocusedColumn.ColumnEdit = Nothing
|
||||
|
||||
' Editor aus RepositoryItems entfernen
|
||||
If oView.GridControl.RepositoryItems.Contains(currentEditor) Then
|
||||
oView.GridControl.RepositoryItems.Remove(currentEditor)
|
||||
_Logger.Debug("[HiddenEditor] Removed editor from RepositoryItems (Remaining: {0})",
|
||||
oView.GridControl.RepositoryItems.Count)
|
||||
End If
|
||||
|
||||
' *** KRITISCH: Dispose aufrufen ***
|
||||
Try
|
||||
currentEditor.Dispose()
|
||||
_Logger.Debug("[HiddenEditor] Disposed editor successfully")
|
||||
Catch disposeEx As Exception
|
||||
_Logger.Warn("[HiddenEditor] Could not dispose editor: {0}", disposeEx.Message)
|
||||
End Try
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
_Logger.Error("[HiddenEditor] Error: {0}", ex.Message)
|
||||
_Logger.Error(ex)
|
||||
End Try
|
||||
End Sub
|
||||
@@ -1237,6 +1376,11 @@ Namespace ControlCreator
|
||||
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Retrieved {0} rows for column [{1}]", oDataTable.Rows.Count, columnName)
|
||||
|
||||
' *** NEU: Log erste 5 Rows für Debugging ***
|
||||
For i As Integer = 0 To Math.Min(4, oDataTable.Rows.Count - 1)
|
||||
_Logger.Debug("[CreateRowSpecificEditor] DataTable Row[{0}]: [{1}]", i, oDataTable.Rows(i)(0))
|
||||
Next
|
||||
|
||||
' Editor erstellen (analog zu GridTables_GetRepositoryItemForColumn)
|
||||
If isAdvancedLookup Then
|
||||
Dim oEditor = New RepositoryItemLookupControl3 With {
|
||||
@@ -1244,6 +1388,8 @@ Namespace ControlCreator
|
||||
.ValueMember = oDataTable.Columns(0).ColumnName,
|
||||
.DataSource = oDataTable
|
||||
}
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Created LookupControl3 with DisplayMember=[{0}], ValueMember=[{1}]",
|
||||
oEditor.DisplayMember, oEditor.ValueMember)
|
||||
Return oEditor
|
||||
Else
|
||||
Dim oEditor = New RepositoryItemComboBox()
|
||||
@@ -1269,8 +1415,10 @@ Namespace ControlCreator
|
||||
|
||||
oEditor.Items.Add(oValue)
|
||||
oItems.Add(oValue)
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Added ComboBox item: [{0}]", oValue)
|
||||
Next
|
||||
|
||||
_Logger.Debug("[CreateRowSpecificEditor] Created ComboBox with {0} items", oEditor.Items.Count)
|
||||
Return oEditor
|
||||
End If
|
||||
|
||||
|
||||
@@ -195,7 +195,10 @@ Public Class frmColumn_Detail
|
||||
CURRENT_INDEX_ID = GUIDTextBox.Text
|
||||
Dim oForm2 As New frmSQLEditor(LOGCONFIG, DatabaseECM) With {
|
||||
.SQLCommand = SQL_COMMANDTextBox.Text,
|
||||
.SQLConnection = 0
|
||||
.SQLConnection = 0,
|
||||
.PlaceholdersManualPrefix = "CTRL",
|
||||
.PlaceholdersManualTitle = "Controls",
|
||||
.PlaceholdersManual = CURRENT_CONTROL_NAME_LIST.ToDictionary(Function(name) name, Function(name) name)
|
||||
}
|
||||
oForm2.ShowDialog()
|
||||
|
||||
@@ -241,7 +244,10 @@ Public Class frmColumn_Detail
|
||||
CURRENT_INDEX_ID = GUIDTextBox.Text
|
||||
Dim oForm2 As New frmSQLEditor(LOGCONFIG, DatabaseECM) With {
|
||||
.SQLCommand = FORMULA_SQLTextBox.Text,
|
||||
.SQLConnection = 0
|
||||
.SQLConnection = 0,
|
||||
.PlaceholdersManualPrefix = "CTRL",
|
||||
.PlaceholdersManualTitle = "Controls",
|
||||
.PlaceholdersManual = CURRENT_CONTROL_NAME_LIST.ToDictionary(Function(name) name, Function(name) name)
|
||||
}
|
||||
oForm2.ShowDialog()
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ Public Class frmFormDesigner
|
||||
Dim oDTColumnsPerDevExGrid As DataTable = DatabaseFallback.GetDatatableECM(oSQL) ', "FDesignLaodControls")
|
||||
|
||||
|
||||
Dim table = ControlCreator.CreateExistingGridControl(row, oDTColumnsPerDevExGrid, True, "EUR")
|
||||
Dim table = ControlCreator.CreateExistingGridControl(row, oDTColumnsPerDevExGrid, True, "EUR", Panel1)
|
||||
|
||||
AddHandler table.MouseClick, AddressOf gridControl_MouseClick
|
||||
' AddHandler table.ColumnHeaderMouseClick, AddressOf table_ColumnHeaderMouseClick
|
||||
|
||||
@@ -354,7 +354,7 @@ Public Class frmMassValidator
|
||||
LOGGER.Debug("Versuch Tabelle zu laden")
|
||||
Dim oDTMyColumns As DataTable = DatabaseFallback.GetDatatableECM($"SELECT * FROM TBPM_CONTROL_TABLE WHERE CONTROL_ID = {oControlRow.Item("GUID")} ORDER BY SEQUENCE") ', "MV_LoadControls1")
|
||||
|
||||
oControl = ControlCreator.CreateExistingGridControl(oControlRow, oDTMyColumns, False, CURRENT_DOC_CURRENCY)
|
||||
oControl = ControlCreator.CreateExistingGridControl(oControlRow, oDTMyColumns, False, CURRENT_DOC_CURRENCY, pnldesigner)
|
||||
End Select
|
||||
|
||||
If oControl IsNot Nothing AndAlso TypeOf oControl IsNot Label Then
|
||||
|
||||
@@ -1675,7 +1675,7 @@ Public Class frmValidator
|
||||
Continue For
|
||||
End If
|
||||
|
||||
Dim oGrid = ControlCreator.CreateExistingGridControl(oControlRow, oFilteredDatatable, False, DocCurrency)
|
||||
Dim oGrid = ControlCreator.CreateExistingGridControl(oControlRow, oFilteredDatatable, False, DocCurrency, PanelValidatorControl)
|
||||
oMyControl = oGrid
|
||||
' NEU: GridView Event registrieren
|
||||
AddHandler DirectCast(oGrid.MainView, GridView).CellValueChanged, AddressOf GridView_CellValueChanged
|
||||
@@ -4447,7 +4447,7 @@ Public Class frmValidator
|
||||
End If
|
||||
|
||||
' GridControl-Helper erstellen und Währungsformat aktualisieren
|
||||
Dim oGridControlHelper As New ControlCreator.GridControl(LOGCONFIG, ControlCreator.GridTables, currencySymbol)
|
||||
Dim oGridControlHelper As New ControlCreator.GridControl(LOGCONFIG, ControlCreator.GridTables, currencySymbol, PanelValidatorControl)
|
||||
oGridControlHelper.UpdateCurrencyFormat(oColumnTable, oView, oGrid, currencySymbol)
|
||||
|
||||
MyValidationLogger.Info("[UpdateGridCurrencyFormats] ✓ Updated GridControl [{0}] to currency [{1}]", oGrid.Name, DocCurrency)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user