Vor SetControlValuesChange

This commit is contained in:
Developer01
2026-03-20 13:43:09 +01:00
parent 969e07eb17
commit c464f24681
9 changed files with 3223 additions and 386 deletions

View File

@@ -68,7 +68,17 @@ Public Class ClassControlCreator
''' </summary> ''' </summary>
Public Property GridTables As New Dictionary(Of Integer, Dictionary(Of String, RepositoryItem)) Public Property GridTables As New Dictionary(Of Integer, Dictionary(Of String, RepositoryItem))
Public Property GridColumns As New Dictionary(Of Integer, DataTable) Public Property GridColumns As New Dictionary(Of Integer, DataTable)
Private _globalLookupEventGuard As Boolean = False
Public Property GlobalLookupEventGuard As Boolean
Get
Return _globalLookupEventGuard
End Get
Set(value As Boolean)
_globalLookupEventGuard = value
Logger.Debug($"GlobalLookupEventGuard -> gesetzt auf [{value}]")
End Set
End Property
''' <summary> ''' <summary>
@@ -853,44 +863,239 @@ Public Class ClassControlCreator
End Function End Function
Public Sub GridTables_HandleControlValueChange(pControlPanel As XtraScrollableControl, pColumnsWithSqlAndControlPlaceholders As DataTable) Public Sub GridTables_HandleControlValueChange(pControlPanel As XtraScrollableControl, pColumnsWithSqlAndControlPlaceholders As DataTable)
If Not IsNothing(pColumnsWithSqlAndControlPlaceholders) AndAlso pColumnsWithSqlAndControlPlaceholders.Rows.Count > 0 Then If pColumnsWithSqlAndControlPlaceholders Is Nothing OrElse pColumnsWithSqlAndControlPlaceholders.Rows.Count = 0 Then
For Each oRow As DataRow In pColumnsWithSqlAndControlPlaceholders.Rows Logger.Debug("No depending controls with SQL statements defined, skipping handling control value change.")
Return
End If
' ============================================================================
' Schritt 1 - Sichere ALLE Lookup-Werte VOR SQL-Reload
' ============================================================================
Dim lookupBackups As New Dictionary(Of String, Object)
For Each oControl As Control In pControlPanel.Controls
If TypeOf oControl Is LookupControl3 Then
Try Try
Dim oSqlStatement = oRow.ItemEx("SQL_COMMAND", String.Empty) Dim lookup = DirectCast(oControl, LookupControl3)
Dim oConnectionId = oRow.ItemEx("CONNECTION_ID", -1) ' Speichere den aktuellen EditValue (kann einzelner Wert oder Liste sein)
Dim oControlId = oRow.Item("CONTROL_ID") If lookup.EditValue IsNot Nothing Then
Dim oColumnName = oRow.Item("SPALTENNAME") Dim controlName As String = lookup.Name
Dim oAdvancedLookup = oRow.Item("ADVANCED_LOOKUP") lookupBackups(controlName) = lookup.EditValue
Logger.Debug($"GridTables_HandleControlValueChange -> Backup für Lookup [{controlName}]: [{lookup.EditValue}]")
If oSqlStatement <> String.Empty And oConnectionId > -1 Then
oSqlStatement = clsPatterns.ReplaceAllValues(oSqlStatement, pControlPanel, True)
GridTables_CacheDatatableForColumn(oControlId, oColumnName, oSqlStatement, oConnectionId, oAdvancedLookup)
' === Block to force setting the editor for GridColumns
Logger.Debug("Force-setting Editor for all Gridcells..")
For Each oControl As Control In pControlPanel.Controls
Try
Dim oMeta = DirectCast(oControl.Tag, ClassControlCreator.ControlMetadata)
If oMeta.Guid = oControlId AndAlso TypeOf oControl Is GridControl Then
Dim oGrid As GridControl = DirectCast(oControl, GridControl)
DirectCast(oGrid.FocusedView, GridView).FocusInvalidRow()
Logger.Debug("Force-setting Editor for Grid [{0}]", oGrid.Name)
Exit For
End If
Catch ex As Exception
Logger.Error(ex)
End Try
Next
' === End
End If End If
Catch ex As Exception Catch ex As Exception
Logger.Error(ex) Logger.Error($"GridTables_HandleControlValueChange -> Fehler beim Backup von Lookup: {ex.Message}")
Logger.Info("Unexpected Error in Display SQL result for grid column: " & oRow.Item("CONTROL_ID") & " - ERROR: " & ex.Message)
End Try End Try
End If
Next
' ============================================================================
' Schritt 2 - Verarbeite Grid-Columns mit SQL-Abhängigkeiten
' ============================================================================
For Each oRow As DataRow In pColumnsWithSqlAndControlPlaceholders.Rows
Try
Dim oSqlStatement = oRow.ItemEx("SQL_COMMAND", String.Empty)
Dim oConnectionId = oRow.ItemEx("CONNECTION_ID", -1)
Dim oControlId = oRow.Item("CONTROL_ID")
Dim oColumnName = oRow.Item("SPALTENNAME")
Dim oAdvancedLookup = oRow.Item("ADVANCED_LOOKUP")
If oSqlStatement <> String.Empty AndAlso oConnectionId > -1 Then
oSqlStatement = clsPatterns.ReplaceAllValues(oSqlStatement, pControlPanel, True)
GridTables_CacheDatatableForColumn(oControlId, oColumnName, oSqlStatement, oConnectionId, oAdvancedLookup)
' Force-setting Editor for GridColumns
Logger.Debug("Force-setting Editor for all Gridcells..")
For Each oControl As Control In pControlPanel.Controls
Try
If oControl.Tag IsNot Nothing AndAlso TypeOf oControl.Tag Is ControlMetadata Then
Dim oMeta = DirectCast(oControl.Tag, ControlMetadata)
If oMeta.Guid = oControlId AndAlso TypeOf oControl Is GridControl Then
Dim oGrid As GridControl = DirectCast(oControl, GridControl)
If oGrid.FocusedView IsNot Nothing AndAlso TypeOf oGrid.FocusedView Is GridView Then
DirectCast(oGrid.FocusedView, GridView).FocusInvalidRow()
Logger.Debug($"Force-setting Editor for Grid [{oGrid.Name}]")
End If
Exit For
End If
End If
Catch ex As Exception
Logger.Error($"GridTables_HandleControlValueChange -> Fehler beim Force-setting Editor: {ex.Message}")
End Try
Next
End If
Catch ex As Exception
Logger.Error(ex)
Logger.Info($"Unexpected Error in Display SQL result for grid column: {oRow.Item("CONTROL_ID")} - ERROR: {ex.Message}")
End Try
Next
' ============================================================================
' Schritt 3 - Prüfe und restauriere Lookup-Werte mit SQL-Abhängigkeiten
' ============================================================================
If lookupBackups.Count > 0 Then
Logger.Debug($"GridTables_HandleControlValueChange -> Prüfe {lookupBackups.Count} Lookups auf Wiederherstellung...")
For Each oControl As Control In pControlPanel.Controls
If TypeOf oControl Is LookupControl3 Then
Try
Dim lookup = DirectCast(oControl, LookupControl3)
Dim controlName As String = lookup.Name
' Wenn wir einen Backup für dieses Lookup haben
If lookupBackups.ContainsKey(controlName) Then
Dim oldValue = lookupBackups(controlName)
' Prüfe ob Lookup ein DataSource hat (könnte durch SQL neu geladen worden sein)
If lookup.Properties.DataSource IsNot Nothing AndAlso TypeOf lookup.Properties.DataSource Is DataTable Then
Dim currentDataSource = DirectCast(lookup.Properties.DataSource, DataTable)
' Wenn DataSource Rows hat, versuche Werte wiederherzustellen
If currentDataSource.Rows.Count > 0 Then
RestoreLookupValues(lookup, oldValue, currentDataSource, controlName)
End If
End If
End If
Catch ex As Exception
Logger.Error($"GridTables_HandleControlValueChange -> Fehler beim Prüfen von Lookup: {ex.Message}")
Logger.Error(ex)
End Try
End If
Next Next
End If End If
End Sub End Sub
Private Sub RestoreLookupValues(lookup As LookupControl3, oldValue As Object,
newDataSource As DataTable, controlName As String)
If lookup Is Nothing OrElse oldValue Is Nothing OrElse newDataSource Is Nothing Then
Logger.Warn($"RestoreLookupValues -> [{controlName}] Ungültige Parameter")
Return
End If
Try
' Bestimme ValueColumn
Dim valueColumn As String = String.Empty
If String.IsNullOrEmpty(lookup.Properties.ValueMember) AndAlso newDataSource.Columns.Count > 0 Then
valueColumn = newDataSource.Columns(0).ColumnName
ElseIf Not String.IsNullOrEmpty(lookup.Properties.ValueMember) Then
valueColumn = lookup.Properties.ValueMember
Else
Logger.Warn($"RestoreLookupValues -> [{controlName}] Keine ValueColumn verfügbar")
Return
End If
' Build HashSet für effiziente Suche
Dim availableValues As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
For Each row As DataRow In newDataSource.Rows
If Not IsDBNull(row(valueColumn)) Then
availableValues.Add(row(valueColumn).ToString())
End If
Next
' Prüfe ob der alte Wert noch in der neuen DataSource existiert
Dim validValue As Object = Nothing
' Behandle verschiedene Datentypen (String, List, Array, etc.)
If TypeOf oldValue Is String Then
Dim valueStr As String = oldValue.ToString()
If availableValues.Contains(valueStr) Then
validValue = oldValue
Logger.Debug($"RestoreLookupValues -> [{controlName}] Wert [{valueStr}] ✓ gefunden")
Else
Logger.Warn($"RestoreLookupValues -> [{controlName}] Wert [{valueStr}] ✗ nicht mehr vorhanden")
End If
ElseIf TypeOf oldValue Is IEnumerable Then
' Behandle Listen/Arrays
Dim validValues As New List(Of Object)
For Each item As Object In DirectCast(oldValue, IEnumerable)
If item IsNot Nothing Then
Dim itemStr As String = item.ToString()
If availableValues.Contains(itemStr) Then
validValues.Add(item)
Logger.Debug($"RestoreLookupValues -> [{controlName}] Wert [{itemStr}] ✓ gefunden")
Else
Logger.Warn($"RestoreLookupValues -> [{controlName}] Wert [{itemStr}] ✗ nicht mehr vorhanden")
End If
End If
Next
If validValues.Count > 0 Then
validValue = validValues
End If
Else
' Fallback für andere Typen
Dim valueStr As String = oldValue.ToString()
If availableValues.Contains(valueStr) Then
validValue = oldValue
Logger.Debug($"RestoreLookupValues -> [{controlName}] Wert [{valueStr}] ✓ gefunden")
Else
Logger.Warn($"RestoreLookupValues -> [{controlName}] Wert [{valueStr}] ✗ nicht mehr vorhanden")
End If
End If
' Gültige Werte wiederherstellen
If validValue IsNot Nothing Then
' Event-Guard temporär aktivieren um Endlosschleifen zu vermeiden
Dim oldGuard As Boolean = GlobalLookupEventGuard
GlobalLookupEventGuard = True
Try
' Prüfe ob bereits korrekt gesetzt
Dim currentValue = lookup.EditValue
If currentValue IsNot Nothing AndAlso currentValue.Equals(validValue) Then
Logger.Debug($"RestoreLookupValues -> [{controlName}] Wert bereits korrekt gesetzt")
Return
End If
' Setze den Wert neu
lookup.EditValue = Nothing
Application.DoEvents()
lookup.EditValue = validValue
lookup.Refresh()
Application.DoEvents()
' Validierung
Dim newValue = lookup.EditValue
If newValue IsNot Nothing AndAlso newValue.Equals(validValue) Then
Logger.Debug($"RestoreLookupValues -> [{controlName}] ✓ erfolgreich wiederhergestellt: [{validValue}]")
Else
Logger.Error($"RestoreLookupValues -> [{controlName}] ✗ Fehler beim Wiederherstellen! Erwartet: [{validValue}], Ist: [{If(newValue, "NULL")}]")
' Retry mit BeginUpdate/EndUpdate
Logger.Debug($"RestoreLookupValues -> [{controlName}] Versuche alternative Methode mit BeginUpdate...")
lookup.Properties.BeginUpdate()
Try
lookup.EditValue = Nothing
Application.DoEvents()
lookup.EditValue = validValue
Finally
lookup.Properties.EndUpdate()
End Try
lookup.Refresh()
Application.DoEvents()
Dim retryValue = lookup.EditValue
If retryValue IsNot Nothing AndAlso retryValue.Equals(validValue) Then
Logger.Debug($"RestoreLookupValues -> [{controlName}] ✓ Alternative Methode erfolgreich")
Else
Logger.Error($"RestoreLookupValues -> [{controlName}] ✗ Auch alternative Methode fehlgeschlagen!")
End If
End If
Finally
' Event-Guard wiederherstellen
GlobalLookupEventGuard = oldGuard
End Try
Else
Logger.Info($"RestoreLookupValues -> [{controlName}] Keine gültigen Werte zum Wiederherstellen")
End If
Catch ex As Exception
Logger.Error($"RestoreLookupValues -> Fehler bei [{controlName}]: {ex.Message}")
Logger.Error(ex)
End Try
End Sub
End Class End Class

View File

@@ -28,13 +28,31 @@ Namespace ControlCreator
Private _FormulaColumnNames As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase) Private _FormulaColumnNames As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
Private _isRefreshingFormula As Boolean = False ' *** NEU: Flag für Formel-Refresh *** Private _isRefreshingFormula As Boolean = False ' *** NEU: Flag für Formel-Refresh ***
Private _currencySymbol As String = "" Private _currencySymbol As String = ""
''' <summary>
''' SHARED Dictionary: Speichert das aktuelle Währungssymbol PRO GridView (via Name).
''' Dies ist notwendig, weil UpdateCurrencyFormat auf einer NEUEN GridControl-Instanz
''' aufgerufen wird, der CustomColumnDisplayText-Handler aber auf der URSPRÜNGLICHEN
''' Instanz registriert wurde. Durch das Shared Dictionary können alle Instanzen
''' auf das aktuelle Symbol zugreifen.
''' </summary>
Private Shared _CurrencySymbolByGridName As New Dictionary(Of String, String)(StringComparer.OrdinalIgnoreCase)
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)
_LogConfig = pLogConfig _LogConfig = pLogConfig
_Logger = pLogConfig.GetLogger() _Logger = pLogConfig.GetLogger()
_GridTables = pGridTables _GridTables = pGridTables
_currencySymbol = pCurrencySymbol _currencySymbol = pCurrencySymbol
End Sub End Sub
''' <summary>
''' Setzt den Shared Currency-Cache zurück. Muss beim Laden eines neuen Dokuments
''' aufgerufen werden, bevor UpdateCurrencyFormat die neuen Werte schreibt.
''' Verhindert, dass ein veraltetes Währungssymbol aus einem vorherigen Dokument
''' durch den CustomColumnDisplayText-Handler verwendet wird.
''' </summary>
Public Shared Sub ResetCurrencySymbolCache()
SyncLock _CurrencySymbolByGridName
_CurrencySymbolByGridName.Clear()
End SyncLock
End Sub
Public Function CreateGridColumns(pColumnTable As DataTable) As DataTable Public Function CreateGridColumns(pColumnTable As DataTable) As DataTable
Dim oDataTable As New DataTable Dim oDataTable As New DataTable
Dim columnsWithExpressions As New List(Of Tuple(Of DataColumn, String)) Dim columnsWithExpressions As New List(Of Tuple(Of DataColumn, String))
@@ -202,15 +220,129 @@ Namespace ControlCreator
Return oEditor Return oEditor
End If End If
End Function End Function
''' <summary>
''' Setzt das Währungssymbol für ein bestimmtes Grid im Shared Cache.
''' Muss bei JEDEM Dokumentwechsel aufgerufen werden (auch bei EUR),
''' damit der CustomColumnDisplayText-Handler sofort den korrekten Wert hat.
''' </summary>
Public Shared Sub SetCurrencySymbolForGrid(gridName As String, currencySymbol As String)
SyncLock _CurrencySymbolByGridName
_CurrencySymbolByGridName(gridName) = currencySymbol
End SyncLock
End Sub
' Hilfsroutine: passt NUR das Summary-Item an (ohne FormatInfo) ' Hilfsroutine: passt NUR das Summary-Item an (ohne FormatInfo)
Private Sub ApplyCurrencySummaryFormat(oCol As GridColumn) Private Sub ApplyCurrencySummaryFormat(oCol As GridColumn)
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
' Variante A: Standard-Währungsformat aus aktueller Kultur _Logger.Debug("Applying currency summary format for column [{0}] with symbol [{1}]", oCol.FieldName, _currencySymbol)
' oCol.SummaryItem.DisplayFormat = "SUM: {0:C2}"
' Variante B: Kulturunabhängig, Symbol explizit anhängen ' Variante B: Kulturunabhängig, Symbol explizit anhängen
oCol.SummaryItem.DisplayFormat = $"SUM: {{0:N2}} {_currencySymbol}" oCol.SummaryItem.DisplayFormat = $"{{0:N2}} {_currencySymbol}"
End Sub End Sub
''' <summary>
''' Aktualisiert die Währungsformatierung für alle CURRENCY-Spalten mit neuem Währungssymbol.
''' Betrifft DisplayFormat, ColumnEdit (für editierbare Spalten) und Summary-Footer.
''' </summary>
''' <summary>
'''
Public Sub UpdateCurrencyFormat(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl, pNewCurrencySymbol As String)
Try
_Logger.Info("[UpdateCurrencyFormat] *** START *** [{0}] → [{1}] für [{2}]", _currencySymbol, pNewCurrencySymbol, pGrid.Name)
' *** KERN-FIX: Speichere Symbol im SHARED Dictionary ***
Dim gridName As String = pGrid.Name
SyncLock _CurrencySymbolByGridName
If _CurrencySymbolByGridName.ContainsKey(gridName) Then
_CurrencySymbolByGridName(gridName) = pNewCurrencySymbol
Else
_CurrencySymbolByGridName.Add(gridName, pNewCurrencySymbol)
End If
End SyncLock
_Logger.Debug("[UpdateCurrencyFormat] Shared Dictionary updated: [{0}] = [{1}]", gridName, pNewCurrencySymbol)
_currencySymbol = pNewCurrencySymbol
Dim oCultureInfo As CultureInfo = New CultureInfo("de-DE")
oCultureInfo.NumberFormat.CurrencySymbol = _currencySymbol
Dim riTextEdit As New RepositoryItemTextEdit()
riTextEdit.MaskSettings.Configure(Of MaskSettings.Numeric)(
Sub(settings)
settings.MaskExpression = "c"
settings.Culture = oCultureInfo
End Sub)
riTextEdit.UseMaskAsDisplayFormat = False
riTextEdit.DisplayFormat.FormatType = FormatType.Custom
riTextEdit.DisplayFormat.FormatString = $"#,##0.00 {_currencySymbol}"
_Logger.Debug("[UpdateCurrencyFormat] riTextEdit: DisplayFormat=[{0}]",
riTextEdit.DisplayFormat.FormatString)
pGridView.BeginUpdate()
Try
' Schritt 1: Altes RepositoryItem entfernen (ohne vorher ColumnEdit=Nothing)
' ColumnEdit NICHT auf Nothing setzen das würde einen Zwischenrender auslösen
Dim oldItems = pGrid.RepositoryItems.OfType(Of RepositoryItemTextEdit)().
Where(Function(item) item.MaskSettings.MaskExpression = "c").ToList()
For Each oldItem In oldItems
_Logger.Debug("[UpdateCurrencyFormat] Removing old riTextEdit: DisplayFormat=[{0}]",
oldItem.DisplayFormat.FormatString)
pGrid.RepositoryItems.Remove(oldItem)
Next
' Schritt 2: CURRENCY-Spalten konfigurieren
For Each oCol As GridColumn In pGridView.Columns
Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{oCol.FieldName}'").
FirstOrDefault()
If oColumnData Is Nothing Then Continue For
If ObjectEx.NotNull(oColumnData.Item("TYPE_COLUMN"), String.Empty).ToString() <> "CURRENCY" Then Continue For
Dim oIsFormula As Boolean =
ObjectEx.NotNull(oColumnData.Item("FORMULA_EXPRESSION"), String.Empty) <> String.Empty
' DisplayFormat immer aktualisieren
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = $"#,##0.00 {_currencySymbol}"
If Not oIsFormula AndAlso oCol.OptionsColumn.AllowEdit Then
' Direkt neues RepositoryItem setzen kein Umweg über RepositoryItems-Collection
oCol.ColumnEdit = riTextEdit
_Logger.Debug("[UpdateCurrencyFormat] ColumnEdit=[{0}] für [{1}]",
DirectCast(oCol.ColumnEdit, RepositoryItemTextEdit).DisplayFormat.FormatString,
oCol.FieldName)
End If
If ObjectEx.NotNull(oColumnData.Item("SUMMARY_FUNCTION"), String.Empty) =
Constants.AGGREGATE_TOTAL_CURRENCY Then
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = $"{{0:N2}} {_currencySymbol}"
End If
Next
Finally
pGridView.EndUpdate()
End Try
' *** KEIN DataSource-Rebind ***
' DataSource-Rebind (pGrid.DataSource = Nothing / = oCurrentDataSource) wirft
' den gecachten Display-Text weg und erzwingt einen Neu-Render durch DevExpress.
' Dabei greift DevExpress auf die Mask-Formatierung des RepositoryItems zurück
' (z.B. "c" mit EUR-Culture) statt auf DisplayFormat → EUR bleibt sichtbar.
' Stattdessen: LayoutChanged + alle Zeilen invalidieren → DevExpress rendert
' die Zellen neu mit dem aktualisierten DisplayFormat und ColumnEdit.
pGridView.LayoutChanged()
For i As Integer = 0 To pGridView.DataRowCount - 1
pGridView.InvalidateRow(i)
Next
pGridView.UpdateTotalSummary()
_Logger.Info("[UpdateCurrencyFormat] *** END *** _currencySymbol=[{0}]", _currencySymbol)
Catch ex As Exception
_Logger.Error("[UpdateCurrencyFormat] Fehler: {0}", ex.Message)
_Logger.Error(ex)
End Try
End Sub
Public Sub ConfigureViewColumns(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl) Public Sub ConfigureViewColumns(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl)
Dim oShouldDisplayFooter As Boolean = False Dim oShouldDisplayFooter As Boolean = False
For Each oCol As GridColumn In pGridView.Columns For Each oCol As GridColumn In pGridView.Columns
@@ -256,8 +388,13 @@ Namespace ControlCreator
oCol.DisplayFormat.FormatString = "N2" oCol.DisplayFormat.FormatString = "N2"
Case "CURRENCY" Case "CURRENCY"
oCol.DisplayFormat.FormatType = FormatType.Custom ' *** DisplayFormat wird NICHT hier gesetzt ***
oCol.DisplayFormat.FormatString = $"N2 {_currencySymbol}" ' ConfigureViewColumnsCurrency übernimmt die CURRENCY-Formatierung
' mit dem korrekten _currencySymbol. Dieses Standardformat würde
' später von UpdateCurrencyFormat überschrieben werden müssen
' für Formel-Spalten (kein ColumnEdit) greift aber nur DisplayFormat,
' weshalb ein falscher Initialwert hier persistent bleibt.
_Logger.Debug("CURRENCY column [{0}]: DisplayFormat wird von ConfigureViewColumnsCurrency gesetzt", oCol.FieldName)
End Select End Select
@@ -266,15 +403,16 @@ Namespace ControlCreator
Select Case oSummaryFunction Select Case oSummaryFunction
Case Constants.AGGREGATE_TOTAL_INTEGER Case Constants.AGGREGATE_TOTAL_INTEGER
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N0}" oCol.SummaryItem.DisplayFormat = "{0:N0}"
oShouldDisplayFooter = True oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_FLOAT Case Constants.AGGREGATE_TOTAL_FLOAT
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N2}" oCol.SummaryItem.DisplayFormat = "{0:N2}"
oShouldDisplayFooter = True oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_CURRENCY Case Constants.AGGREGATE_TOTAL_CURRENCY
_Logger.Debug(Of String)("Applying currency summary format for column [{0}]", oCol.FieldName)
ApplyCurrencySummaryFormat(oCol) ApplyCurrencySummaryFormat(oCol)
oShouldDisplayFooter = True oShouldDisplayFooter = True
@@ -311,49 +449,140 @@ Namespace ControlCreator
End If End If
End Sub End Sub
Public Sub ConfigureViewColumnsCurrency(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl) Public Sub ConfigureViewColumnsCurrency(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl)
Dim oCultureInfo As CultureInfo = New CultureInfo("de-DE") Dim oCultureInfo As CultureInfo = New CultureInfo("de-DE")
oCultureInfo.NumberFormat.CurrencySymbol = _currencySymbol oCultureInfo.NumberFormat.CurrencySymbol = _currencySymbol
Dim riTextEdit As RepositoryItemTextEdit = New RepositoryItemTextEdit() Dim riTextEdit As RepositoryItemTextEdit = New RepositoryItemTextEdit()
riTextEdit.MaskSettings.Configure(Of MaskSettings.Numeric)(Sub(settings) riTextEdit.MaskSettings.Configure(Of MaskSettings.Numeric)(
settings.MaskExpression = "c" Sub(settings)
settings.Culture = oCultureInfo settings.MaskExpression = "c"
End Sub) settings.Culture = oCultureInfo
riTextEdit.UseMaskAsDisplayFormat = True End Sub)
pGrid.RepositoryItems.Add(riTextEdit) riTextEdit.UseMaskAsDisplayFormat = False
riTextEdit.DisplayFormat.FormatType = FormatType.Custom
riTextEdit.DisplayFormat.FormatString = $"#,##0.00 {_currencySymbol}"
' *** DIAGNOSE 1: Zustand der RepositoryItems VOR der Zuweisung ***
_Logger.Debug("[ConfigureViewColumnsCurrency] riTextEdit erstellt: DisplayFormat=[{0}], HashCode=[{1}]",
riTextEdit.DisplayFormat.FormatString, riTextEdit.GetHashCode())
_Logger.Debug("[ConfigureViewColumnsCurrency] pGrid.RepositoryItems.Count VOR Schleife=[{0}]",
pGrid.RepositoryItems.Count)
For Each oCol As GridColumn In pGridView.Columns For Each oCol As GridColumn In pGridView.Columns
Dim oColumnData As DataRow = pColumnTable. Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{oCol.FieldName}'"). Select($"SPALTENNAME = '{oCol.FieldName}'").
FirstOrDefault() FirstOrDefault()
If oColumnData Is Nothing Then Continue For
If oColumnData Is Nothing Then Dim oColumnType As String = ObjectEx.NotNull(oColumnData.Item("TYPE_COLUMN"), String.Empty).ToString()
Continue For If oColumnType <> "CURRENCY" Then Continue For
End If
' *** NEU: Prüfe ob Spalte editierbar ist ***
If Not oCol.OptionsColumn.AllowEdit Then
_Logger.Debug("Skipping ColumnEdit for read-only column [{0}]", oCol.FieldName)
Continue For
End If
' Formel-Spalten dürfen kein ColumnEdit bekommen, da der RepositoryItem-Cache
' den berechneten Wert nach RefreshRowCell überschreibt.
Dim oFormulaExpression = ObjectEx.NotNull(oColumnData.Item("FORMULA_EXPRESSION"), String.Empty) Dim oFormulaExpression = ObjectEx.NotNull(oColumnData.Item("FORMULA_EXPRESSION"), String.Empty)
If oFormulaExpression <> String.Empty Then Dim oIsFormula As Boolean = oFormulaExpression <> String.Empty
_Logger.Debug("Skipping ColumnEdit assignment for formula column [{0}] using DisplayFormat only.", oCol.FieldName)
Continue For If oIsFormula Then
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = $"#,##0.00 {_currencySymbol}"
_Logger.Debug("[ConfigureViewColumnsCurrency] Formel-Spalte [{0}]: DisplayFormat=[{1}], RepositoryItems.Count=[{2}]",
oCol.FieldName, oCol.DisplayFormat.FormatString, pGrid.RepositoryItems.Count)
ElseIf oCol.OptionsColumn.AllowEdit Then
' *** DIAGNOSE 2: RepositoryItems-Count VOR und NACH ColumnEdit-Zuweisung ***
_Logger.Debug("[ConfigureViewColumnsCurrency] [{0}] VOR ColumnEdit: RepositoryItems.Count=[{1}]",
oCol.FieldName, pGrid.RepositoryItems.Count)
oCol.ColumnEdit = riTextEdit
' *** DIAGNOSE 3: Prüfen ob DevExpress das Item intern zu RepositoryItems hinzugefügt hat ***
_Logger.Debug("[ConfigureViewColumnsCurrency] [{0}] NACH ColumnEdit: RepositoryItems.Count=[{1}]",
oCol.FieldName, pGrid.RepositoryItems.Count)
Dim assignedEdit = TryCast(oCol.ColumnEdit, RepositoryItemTextEdit)
_Logger.Debug("[ConfigureViewColumnsCurrency] [{0}]: IsSameObject=[{1}], ColumnEdit.DisplayFormat=[{2}], ColumnEdit.HashCode=[{3}]",
oCol.FieldName,
Object.ReferenceEquals(assignedEdit, riTextEdit),
If(assignedEdit IsNot Nothing, assignedEdit.DisplayFormat.FormatString, "N/A"),
If(assignedEdit IsNot Nothing, assignedEdit.GetHashCode(), -1))
' *** DIAGNOSE 4: Alle Items in RepositoryItems ausgeben ***
For i As Integer = 0 To pGrid.RepositoryItems.Count - 1
_Logger.Debug("[ConfigureViewColumnsCurrency] RepositoryItems[{0}]: Type=[{1}], HashCode=[{2}]",
i, pGrid.RepositoryItems(i).GetType().Name, pGrid.RepositoryItems(i).GetHashCode())
Next
End If
Next
' *** DIAGNOSE 5: CustomColumnDisplayText feuert es überhaupt? ***
' Temporär direkt hier einen einmaligen Test-Handler registrieren
Dim oTestFired As Boolean = False
AddHandler pGridView.CustomColumnDisplayText,
Sub(sender As Object, e As CustomColumnDisplayTextEventArgs)
If e.Column Is Nothing OrElse e.Value Is Nothing OrElse IsDBNull(e.Value) Then
Return
End If End If
Dim oColumnType As String = oColumnData.Item("TYPE_COLUMN") ' Prüfe ob Spalte vom Typ CURRENCY ist
Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{e.Column.FieldName}'").
FirstOrDefault()
Select Case oColumnType If oColumnData IsNot Nothing AndAlso
Case "CURRENCY" oColumnData.Item("TYPE_COLUMN").ToString() = "CURRENCY" Then
' *** WICHTIG: NUR ColumnEdit setzen, KEIN DisplayFormat mehr! ***
oCol.ColumnEdit = riTextEdit Try
End Select ' *** KERN-FIX: Hole Symbol aus SHARED Dictionary statt Instanz-Feld ***
Next Dim currentSymbol As String = _currencySymbol ' Fallback
Dim gridName As String = pGrid.Name ' <-- FIX: pGrid statt pControl
SyncLock _CurrencySymbolByGridName
If _CurrencySymbolByGridName.ContainsKey(gridName) Then
currentSymbol = _CurrencySymbolByGridName(gridName)
End If
End SyncLock
Dim oValue As Double
' *** KRITISCH: Robustes Parsing unabhängig vom Dezimaltrenner ***
If TypeOf e.Value Is Double OrElse TypeOf e.Value Is Decimal Then
oValue = Convert.ToDouble(e.Value)
ElseIf TypeOf e.Value Is String Then
Dim oStringValue As String = e.Value.ToString().Trim()
' Versuche zuerst deutsches Format (1.234,56)
Dim oDeCulture As CultureInfo = New CultureInfo("de-DE")
If Double.TryParse(oStringValue, NumberStyles.Currency Or NumberStyles.Number, oDeCulture, oValue) Then
' Erfolgreich mit deutschem Format geparst
ElseIf Double.TryParse(oStringValue, NumberStyles.Currency Or NumberStyles.Number, CultureInfo.InvariantCulture, oValue) Then
' Erfolgreich mit invariantem Format (Punkt als Dezimaltrenner)
Else
' Fallback: Systemkultur
oValue = Convert.ToDouble(oStringValue, CultureInfo.CurrentCulture)
End If
Else
oValue = Convert.ToDouble(e.Value)
End If
' Formatierung IMMER mit deutscher Kultur (Komma als Dezimaltrenner)
Dim oDeCultureInfo As CultureInfo = New CultureInfo("de-DE")
e.DisplayText = oValue.ToString("N2", oDeCultureInfo) & " " & currentSymbol
_Logger.Debug("[CustomColumnDisplayText] CURRENCY [{0}]: DisplayText=[{1}], Symbol=[{2}] (from Shared Dict in ConfigureViewColumnsCurrency)",
e.Column.FieldName, e.DisplayText, currentSymbol)
Catch ex As Exception
_Logger.Warn("⚠️ Could not format currency value [{0}] for column [{1}]: {2}",
e.Value, e.Column.FieldName, ex.Message)
' Fallback: Original-Wert + Symbol
Dim fallbackSymbol As String = _currencySymbol
SyncLock _CurrencySymbolByGridName
If _CurrencySymbolByGridName.ContainsKey(pGrid.Name) Then ' <-- FIX: pGrid statt pControl
fallbackSymbol = _CurrencySymbolByGridName(pGrid.Name)
End If
End SyncLock
e.DisplayText = e.Value.ToString() & " " & fallbackSymbol
End Try
End If
End Sub
End Sub End Sub
Public Sub ConfigureViewEvents(pColumnTable As DataTable, pGridView As GridView, pControl As Windows.Forms.Control, pControlId As Integer) Public Sub ConfigureViewEvents(pColumnTable As DataTable, pGridView As GridView, pControl As Windows.Forms.Control, pControlId As Integer)
' Formel-Spalten-Namen einmalig cachen für View_ShowingEditor ' Formel-Spalten-Namen einmalig cachen für View_ShowingEditor
_FormulaColumnNames.Clear() _FormulaColumnNames.Clear()
@@ -405,6 +634,15 @@ Namespace ControlCreator
oColumnData.Item("TYPE_COLUMN").ToString() = "CURRENCY" Then oColumnData.Item("TYPE_COLUMN").ToString() = "CURRENCY" Then
Try Try
' *** KERN-FIX: Hole Symbol aus SHARED Dictionary statt Instanz-Feld ***
Dim currentSymbol As String = _currencySymbol ' Fallback
Dim gridName As String = pControl.Name
SyncLock _CurrencySymbolByGridName
If _CurrencySymbolByGridName.ContainsKey(gridName) Then
currentSymbol = _CurrencySymbolByGridName(gridName)
End If
End SyncLock
Dim oValue As Double Dim oValue As Double
' *** KRITISCH: Robustes Parsing unabhängig vom Dezimaltrenner *** ' *** KRITISCH: Robustes Parsing unabhängig vom Dezimaltrenner ***
If TypeOf e.Value Is Double OrElse TypeOf e.Value Is Decimal Then If TypeOf e.Value Is Double OrElse TypeOf e.Value Is Decimal Then
@@ -428,13 +666,22 @@ Namespace ControlCreator
' Formatierung IMMER mit deutscher Kultur (Komma als Dezimaltrenner) ' Formatierung IMMER mit deutscher Kultur (Komma als Dezimaltrenner)
Dim oDeCultureInfo As CultureInfo = New CultureInfo("de-DE") Dim oDeCultureInfo As CultureInfo = New CultureInfo("de-DE")
e.DisplayText = oValue.ToString("N2", oDeCultureInfo) & " " & _currencySymbol e.DisplayText = oValue.ToString("N2", oDeCultureInfo) & " " & currentSymbol
_Logger.Debug("[CustomColumnDisplayText] CURRENCY [{0}]: DisplayText=[{1}], Symbol=[{2}] (from Shared Dict in ConfigureViewEvents)",
e.Column.FieldName, e.DisplayText, currentSymbol)
Catch ex As Exception Catch ex As Exception
_Logger.Warn("⚠️ Could not format currency value [{0}] for column [{1}]: {2}", _Logger.Warn("⚠️ Could not format currency value [{0}] for column [{1}]: {2}",
e.Value, e.Column.FieldName, ex.Message) e.Value, e.Column.FieldName, ex.Message)
' Fallback: Original-Wert + Symbol ' Fallback: Original-Wert + Symbol
e.DisplayText = e.Value.ToString() & " " & _currencySymbol Dim fallbackSymbol As String = _currencySymbol
SyncLock _CurrencySymbolByGridName
If _CurrencySymbolByGridName.ContainsKey(pControl.Name) Then
fallbackSymbol = _CurrencySymbolByGridName(pControl.Name)
End If
End SyncLock
e.DisplayText = e.Value.ToString() & " " & fallbackSymbol
End Try End Try
End If End If
End Sub End Sub
@@ -442,19 +689,47 @@ Namespace ControlCreator
AddHandler pGridView.CustomRowCellEdit, Sub(sender As Object, e As CustomRowCellEditEventArgs) AddHandler pGridView.CustomRowCellEdit, Sub(sender As Object, e As CustomRowCellEditEventArgs)
Try Try
For Each oRow As DataRow In pColumnTable.Rows For Each oRow As DataRow In pColumnTable.Rows
Dim oColumnName = oRow.Item("SPALTENNAME") Dim oColumnName As String = oRow.Item("SPALTENNAME").ToString()
If oColumnName <> e.Column.FieldName Then Continue For
Dim oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, oColumnName) Dim oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, oColumnName)
If oColumnName <> e.Column.FieldName Then
Continue For
End If
If oEditorExists Then If oEditorExists Then
' Combobox/Lookup-Editor aus GridTables: immer zuweisen
Dim oEditor = _GridTables.Item(pControlId).Item(oColumnName) Dim oEditor = _GridTables.Item(pControlId).Item(oColumnName)
_Logger.Debug("Assigning Editor to Column [{0}]", oColumnName) _Logger.Debug("Assigning Editor to Column [{0}]", oColumnName)
e.RepositoryItem = oEditor e.RepositoryItem = oEditor
Else Else
_Logger.Debug("Editor for Column [{0}] does not exist", oColumnName) Dim oColumnType As String = ObjectEx.NotNull(oRow.Item("TYPE_COLUMN"), String.Empty).ToString()
If oColumnType = "CURRENCY" Then
' *** KERN-FIX ***
' Für CURRENCY-Spalten wird e.RepositoryItem NIEMALS gesetzt.
'
' Grund: Sobald e.RepositoryItem gesetzt ist, übernimmt das
' RepositoryItem die komplette Zelldarstellung DevExpress
' übergeht CustomColumnDisplayText vollständig. Das RepositoryItem
' verwendet intern die Mask-Culture ("c" = EUR) zur Anzeige,
' unabhängig von DisplayFormat oder _currencySymbol.
'
' Korrekte Architektur:
' - Anzeige (nicht editiert): CustomColumnDisplayText
' → formatiert mit _currencySymbol (CHF)
' - Bearbeitung (editiert): ColumnEdit an der GridColumn
' → wird von DevExpress beim Öffnen
' des Editors automatisch verwendet
'
' CustomRowCellEdit muss NICHT eingreifen GridColumn.ColumnEdit
' ist bereits gesetzt und wird für den Editiermodus korrekt genutzt.
If _FormulaColumnNames.Contains(oColumnName) Then
_Logger.Debug("CURRENCY column [{0}] is formula/readonly CustomColumnDisplayText handles display", oColumnName)
Else
_Logger.Debug("CURRENCY column [{0}] NO e.RepositoryItem set. Display via CustomColumnDisplayText, Edit via GridColumn.ColumnEdit", oColumnName)
End If
Else
_Logger.Debug("Editor for Column [{0}] does not exist", oColumnName)
End If
End If End If
Exit For
Next Next
Catch ex As Exception Catch ex As Exception
_Logger.Warn("⚠️ Error in CustomRowCellEdit for [{0}]", e.CellValue) _Logger.Warn("⚠️ Error in CustomRowCellEdit for [{0}]", e.CellValue)

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,6 @@ Imports System.Runtime.InteropServices
' übernehmen, indem Sie "*" eingeben: ' übernehmen, indem Sie "*" eingeben:
' <Assembly: AssemblyVersion("1.0.*")> ' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2.8.4.0")> <Assembly: AssemblyVersion("2.8.5.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")> <Assembly: AssemblyFileVersion("1.0.0.0")>
<Assembly: NeutralResourcesLanguage("")> <Assembly: NeutralResourcesLanguage("")>

View File

@@ -1284,6 +1284,7 @@
<Content Include="DataColumnExpression.txt" /> <Content Include="DataColumnExpression.txt" />
<Content Include="DD_Icons_ICO_PMANAGER_48px.ico" /> <Content Include="DD_Icons_ICO_PMANAGER_48px.ico" />
<Content Include="DD_taskFLOW_ICON.ico" /> <Content Include="DD_taskFLOW_ICON.ico" />
<Content Include="Log_Waehrung.txt" />
<Content Include="MailLicense.xml"> <Content Include="MailLicense.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

View File

@@ -1,10 +1,11 @@
Imports System.Text.RegularExpressions Imports System.Text.RegularExpressions
Imports WINDREAMLib Imports DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper
Imports DigitalData.Controls.LookupGrid
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Views.Grid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraEditors Imports DevExpress.XtraEditors
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraGrid.Views.Grid
Imports DigitalData.Controls.LookupGrid
Imports WINDREAMLib
''' <summary> ''' <summary>
''' Defines common Functions for Checking for and replacing placeholders. ''' Defines common Functions for Checking for and replacing placeholders.
''' This Class also includes a child class `Pattern` for passing around Patterns. ''' This Class also includes a child class `Pattern` for passing around Patterns.
@@ -150,34 +151,39 @@ Public Class clsPatterns
End Function End Function
Public Shared Function ReplaceAllValues(input As String, panel As DevExpress.XtraEditors.XtraScrollableControl, is_SQL As Boolean) As String Public Shared Function ReplaceAllValues(input As String, panel As DevExpress.XtraEditors.XtraScrollableControl, is_SQL As Boolean) As String
Dim oResult = input
Try Try
Dim result = input
If Not HasAnyPatterns(result) Then If Not HasAnyPatterns(oResult) Then
Return result Return oResult
End If End If
LOGGER.Debug($"input BEFORE replacing: [{result}]") LOGGER.Debug($"input BEFORE replacing: [{oResult}]")
result = ReplaceInternalValues(result) oResult = ReplaceInternalValues(oResult)
If Not IsNothing(CURRENT_WMFILE) Then If Not IsNothing(CURRENT_WMFILE) Then
result = ReplaceWindreamIndicies(result, CURRENT_WMFILE, is_SQL) oResult = ReplaceWindreamIndicies(oResult, CURRENT_WMFILE, is_SQL)
End If End If
If IDB_ACTIVE = True Then If IDB_ACTIVE = True Then
result = ReplaceIDBAttributes(result, is_SQL) oResult = ReplaceIDBAttributes(oResult, is_SQL)
End If End If
'vorher hinter result = ReplaceInternalValues(result) 'vorher hinter result = ReplaceInternalValues(result)
result = ReplaceControlValues(result, panel, is_SQL) oResult = ReplaceControlValues(oResult, panel, is_SQL)
If Not IsNothing(result) Then If Not IsNothing(oResult) Then
result = ReplaceUserValues(result) oResult = ReplaceUserValues(oResult)
LOGGER.Debug($"input AFTER replacing: [{result}]") LOGGER.Debug($"input AFTER replacing: [{oResult}]")
End If End If
Return result Return oResult
Catch ex As Exception Catch ex As Exception
LOGGER.Error(ex) LOGGER.Error(ex)
LOGGER.Info("Error in ReplaceAllValues:" & ex.Message) LOGGER.Error($"❌ CRITICAL ERROR in ReplaceAllValues!")
LOGGER.Error($" Input: [{input}]")
LOGGER.Error($" Last successful result: [{oResult}]")
LOGGER.Error($" Exception Type: [{ex.GetType().Name}]")
LOGGER.Error($" Message: [{ex.Message}]")
LOGGER.Error($" StackTrace: [{ex.StackTrace}]")
Return input Return input
End Try End Try
End Function End Function
@@ -354,12 +360,28 @@ Public Class clsPatterns
Case GetType(LookupControl3) Case GetType(LookupControl3)
Dim oLookupControl3 As LookupControl3 = oControl Dim oLookupControl3 As LookupControl3 = oControl
If oLookupControl3.Properties.SelectedValues.Count > 1 Then
LOGGER.Debug($"LookupControl3 mit mehr als 1 Value")
Dim oIndex As Integer = 0
For Each oString As String In oLookupControl3.Properties.SelectedValues
If oIndex = 0 Then
' ========== FIX START: NULL-Check ==========
Dim selectedValues As List(Of String) = Nothing
Try
selectedValues = oLookupControl3.Properties.SelectedValues
Catch ex As Exception
LOGGER.Warn($"⚠️ LookupControl [{oControlName}] SelectedValues not accessible: {ex.Message}")
selectedValues = Nothing
End Try
If selectedValues Is Nothing Then
LOGGER.Warn($"⚠️ LookupControl [{oControlName}] SelectedValues is Nothing! Using ERROR_REPLACE_VALUE")
oReplaceValue = ERROR_REPLACE_VALUE
ElseIf selectedValues.Count = 0 Then
LOGGER.Warn($"⚠️ LookupControl [{oControlName}] SelectedValues is empty! Using ERROR_REPLACE_VALUE")
oReplaceValue = ERROR_REPLACE_VALUE
' ========== FIX END ==========
ElseIf selectedValues.Count > 1 Then
LOGGER.Debug($"LookupControl3 [{oControlName}] mit mehr als 1 Value")
Dim oIndex As Integer = 0
For Each oString As String In selectedValues
If oIndex = 0 Then
oReplaceValue = oString oReplaceValue = oString
Else Else
oReplaceValue += "', '" + oString oReplaceValue += "', '" + oString
@@ -367,13 +389,12 @@ Public Class clsPatterns
oIndex += 1 oIndex += 1
Next Next
oIsSQL = False oIsSQL = False
ElseIf oLookupControl3.Properties.SelectedValues.Count = 1 Then Else ' Count = 1
LOGGER.Debug($"LookupControl3 mit genau einem Value") LOGGER.Debug($"LookupControl3 [{oControlName}] mit genau einem Value")
oReplaceValue = oLookupControl3.Properties.SelectedValues(0) oReplaceValue = selectedValues(0)
Else
' LOGGER.Warn($"SelectedValues of LookUpControl scheint empty oder leer zu sein! Ersetzen mit ErrorReplaceValue!")
oReplaceValue = ERROR_REPLACE_VALUE
End If End If
LOGGER.Debug($"oReplaceValue nach Durchlaufen selectedValues: {oReplaceValue}")
LOGGER.Debug($"oReplaceValue nach Durchlaufen selectedValues: {oReplaceValue}") LOGGER.Debug($"oReplaceValue nach Durchlaufen selectedValues: {oReplaceValue}")
Case GetType(Windows.Forms.ComboBox) Case GetType(Windows.Forms.ComboBox)
@@ -381,7 +402,7 @@ Public Class clsPatterns
Case GetType(CheckBox) Case GetType(CheckBox)
Dim oCheckBox As CheckBox = oControl Dim oCheckBox As CheckBox = oControl
oReplaceValue = oCheckBox.Checked oReplaceValue = If(oCheckBox.Checked, "1", "0") ' Explizite String-Konvertierung
Case GetType(GridControl) Case GetType(GridControl)
Dim oGrid As GridControl = oControl Dim oGrid As GridControl = oControl
@@ -406,10 +427,18 @@ Public Class clsPatterns
Case Else Case Else
oReplaceValue = ERROR_REPLACE_VALUE oReplaceValue = ERROR_REPLACE_VALUE
End Select End Select
LOGGER.Debug($"[SQL-ESCAPE CHECK] Control: [{oControlName}], oReplaceValue Type: [{If(oReplaceValue?.GetType()?.Name, "NULL")}], Value: [{oReplaceValue}], IsSQL: [{oIsSQL}]")
If oReplaceValue Is Nothing Then
LOGGER.Warn($"⚠️ oReplaceValue is Nothing for control [{oControlName}]! Setting to ERROR_REPLACE_VALUE")
oReplaceValue = ERROR_REPLACE_VALUE
End If
If Not TypeOf oReplaceValue Is String Then
LOGGER.Warn($"⚠️ oReplaceValue is not a String for control [{oControlName}]! Type: [{oReplaceValue.GetType().Name}]. Converting to String.")
oReplaceValue = oReplaceValue.ToString()
End If
If oIsSQL = True Then If oIsSQL = True Then
'LOGGER.Debug($"IS_SQL = True - oReplaceValue = {oReplaceValue}") oReplaceValue = SafeSqlEscape(oReplaceValue)
'LOGGER.Debug($"oReplaceValue = {oReplaceValue}")
oReplaceValue = oReplaceValue.Replace("'", "''")
End If End If
oResult = ReplacePattern(oResult, PATTERN_CTRL, oReplaceValue) oResult = ReplacePattern(oResult, PATTERN_CTRL, oReplaceValue)
Else Else
@@ -425,16 +454,46 @@ Public Class clsPatterns
Return oResult Return oResult
End Try End Try
End Function End Function
Private Shared Function SafeSqlEscape(value As Object) As String
LOGGER.Debug($"[SafeSqlEscape] Input Type: [{If(value?.GetType()?.Name, "NULL")}], Value: [{value}]")
If value Is Nothing Then
LOGGER.Warn("[SafeSqlEscape] Value is Nothing → returning ERROR_REPLACE_VALUE")
Return ERROR_REPLACE_VALUE
End If
Dim strValue As String
Try
strValue = value.ToString()
Catch ex As Exception
LOGGER.Error(ex)
LOGGER.Warn($"[SafeSqlEscape] ToString() failed: {ex.Message} → returning ERROR_REPLACE_VALUE")
Return ERROR_REPLACE_VALUE
End Try
If String.IsNullOrEmpty(strValue) Then
LOGGER.Warn("[SafeSqlEscape] String is empty → returning ERROR_REPLACE_VALUE")
Return ERROR_REPLACE_VALUE
End If
Dim escaped = strValue.Replace("'", "''")
LOGGER.Debug($"[SafeSqlEscape] Output: [{escaped}]")
Return escaped
End Function
Public Shared Function ReplaceWindreamIndicies(pInput As String, pDocument As WMObject, pIsSQL As Boolean) As String Public Shared Function ReplaceWindreamIndicies(pInput As String, pDocument As WMObject, pIsSQL As Boolean) As String
Try Try
Dim oResult = pInput Dim oResult = pInput
Dim oTryCounter As Integer = 0 Dim oTryCounter As Integer = 0
While ContainsPattern(oResult, PATTERN_WMI) While ContainsPattern(oResult, PATTERN_WMI)
Dim oWMValue As String
Dim oIndexName As String = GetNextPattern(oResult, PATTERN_WMI).Value Dim oIndexName As String = GetNextPattern(oResult, PATTERN_WMI).Value
Dim oWMValue As String = pDocument.GetVariableValue(oIndexName) If oIndexName = "@@DISPLAY_ONLY" Then
oWMValue = String.Empty
Else
oWMValue = pDocument.GetVariableValue(oIndexName)
End If
If IsNothing(oWMValue) And oTryCounter = MAX_TRY_COUNT Then If IsNothing(oWMValue) And oTryCounter = MAX_TRY_COUNT Then
Throw New Exception("Max tries in ReplaceWindreamIndicies exceeded.") Throw New Exception("Max tries in ReplaceWindreamIndicies exceeded.")

View File

@@ -125,7 +125,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADw ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADw
CAAAAk1TRnQBSQFMAgEBAgEAAfABCwHwAQsBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo CAAAAk1TRnQBSQFMAgEBAgEAAfgBCwH4AQsBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
@@ -1506,13 +1506,13 @@
<value>Aktionen</value> <value>Aktionen</value>
</data> </data>
<data name="RibbonControl1.Size" type="System.Drawing.Size, System.Drawing"> <data name="RibbonControl1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 158</value> <value>1178, 126</value>
</data> </data>
<data name="RibbonStatusBar1.Location" type="System.Drawing.Point, System.Drawing"> <data name="RibbonStatusBar1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 666</value> <value>0, 670</value>
</data> </data>
<data name="RibbonStatusBar1.Size" type="System.Drawing.Size, System.Drawing"> <data name="RibbonStatusBar1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 22</value> <value>1178, 18</value>
</data> </data>
<data name="&gt;&gt;RibbonStatusBar1.Name" xml:space="preserve"> <data name="&gt;&gt;RibbonStatusBar1.Name" xml:space="preserve">
<value>RibbonStatusBar1</value> <value>RibbonStatusBar1</value>
@@ -1539,7 +1539,7 @@
<value>4</value> <value>4</value>
</data> </data>
<data name="GridControlWorkflows.Size" type="System.Drawing.Size, System.Drawing"> <data name="GridControlWorkflows.Size" type="System.Drawing.Size, System.Drawing">
<value>945, 484</value> <value>945, 549</value>
</data> </data>
<data name="GridControlWorkflows.TabIndex" type="System.Int32, mscorlib"> <data name="GridControlWorkflows.TabIndex" type="System.Int32, mscorlib">
<value>10</value> <value>10</value>
@@ -1782,7 +1782,7 @@
<value>233</value> <value>233</value>
</data> </data>
<data name="NavBarControl1.Size" type="System.Drawing.Size, System.Drawing"> <data name="NavBarControl1.Size" type="System.Drawing.Size, System.Drawing">
<value>233, 508</value> <value>233, 573</value>
</data> </data>
<data name="NavBarControl1.TabIndex" type="System.Int32, mscorlib"> <data name="NavBarControl1.TabIndex" type="System.Int32, mscorlib">
<value>5</value> <value>5</value>
@@ -1809,10 +1809,10 @@
<value>Tahoma, 9pt</value> <value>Tahoma, 9pt</value>
</data> </data>
<data name="Panel1.Location" type="System.Drawing.Point, System.Drawing"> <data name="Panel1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 158</value> <value>0, 101</value>
</data> </data>
<data name="Panel1.Size" type="System.Drawing.Size, System.Drawing"> <data name="Panel1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 508</value> <value>1178, 573</value>
</data> </data>
<data name="Panel1.TabIndex" type="System.Int32, mscorlib"> <data name="Panel1.TabIndex" type="System.Int32, mscorlib">
<value>4</value> <value>4</value>
@@ -2111,7 +2111,7 @@
<value>9, 19</value> <value>9, 19</value>
</data> </data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>1178, 688</value> <value>1473, 860</value>
</data> </data>
<data name="$this.Font" type="System.Drawing.Font, System.Drawing"> <data name="$this.Font" type="System.Drawing.Font, System.Drawing">
<value>Tahoma, 12pt</value> <value>Tahoma, 12pt</value>

File diff suppressed because it is too large Load Diff

View File

@@ -468,7 +468,55 @@ Public Class frmValidatorSearch
ToolStripDropDownButtonFile.Visible = False ToolStripDropDownButtonFile.Visible = False
End Sub End Sub
Private Sub EnsureFormIsVisible()
Try
' Aktuellen Bildschirm basierend auf der Formularposition ermitteln
Dim currentScreen As Screen = Screen.FromPoint(Me.Location)
Dim workingArea As Rectangle = currentScreen.WorkingArea
' Prüfen ob das Formular vollständig außerhalb des sichtbaren Bereichs liegt
Dim formBounds As New Rectangle(Me.Location, Me.Size)
' Wenn das Formular nicht mit dem Arbeitsbereich überschneidet
If Not workingArea.IntersectsWith(formBounds) Then
CenterFormOnScreen()
Exit Sub
End If
' Optional: Prüfen ob das Formular zu weit außerhalb liegt (z.B. nur 20% sichtbar)
Dim visibleArea As Rectangle = Rectangle.Intersect(workingArea, formBounds)
Dim visiblePercentage As Double = (visibleArea.Width * visibleArea.Height) / (formBounds.Width * formBounds.Height)
If visiblePercentage < 0.2 Then ' Weniger als 20% sichtbar
CenterFormOnScreen()
End If
Catch ex As Exception
LOGGER.Error(ex)
' Bei Fehler sicherheitshalber zentrieren
CenterFormOnScreen()
End Try
End Sub
Private Sub CenterFormOnScreen()
Try
' Formular auf dem primären Bildschirm zentrieren
Me.StartPosition = FormStartPosition.CenterScreen
' Alternative: Auf aktuellem Bildschirm zentrieren
Dim currentScreen As Screen = Screen.PrimaryScreen
Dim x As Integer = currentScreen.WorkingArea.Left + (currentScreen.WorkingArea.Width - Me.Width) \ 2
Dim y As Integer = currentScreen.WorkingArea.Top + (currentScreen.WorkingArea.Height - Me.Height) \ 2
Me.Location = New Point(x, y)
LOGGER.Info("Formular wurde zentriert, da es außerhalb des sichtbaren Bereichs lag")
Catch ex As Exception
LOGGER.Error(ex)
End Try
End Sub
Private Sub frmValidatorSearch_Shown(sender As Object, e As EventArgs) Handles Me.Shown Private Sub frmValidatorSearch_Shown(sender As Object, e As EventArgs) Handles Me.Shown
' Prüfen ob das Formular im sichtbaren Bereich liegt
EnsureFormIsVisible()
formLoaded = True formLoaded = True
End Sub End Sub