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>
Public Property GridTables As New Dictionary(Of Integer, Dictionary(Of String, RepositoryItem))
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>
@@ -853,44 +863,239 @@ Public Class ClassControlCreator
End Function
Public Sub GridTables_HandleControlValueChange(pControlPanel As XtraScrollableControl, pColumnsWithSqlAndControlPlaceholders As DataTable)
If Not IsNothing(pColumnsWithSqlAndControlPlaceholders) AndAlso pColumnsWithSqlAndControlPlaceholders.Rows.Count > 0 Then
For Each oRow As DataRow In pColumnsWithSqlAndControlPlaceholders.Rows
If pColumnsWithSqlAndControlPlaceholders Is Nothing OrElse pColumnsWithSqlAndControlPlaceholders.Rows.Count = 0 Then
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
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 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
Dim lookup = DirectCast(oControl, LookupControl3)
' Speichere den aktuellen EditValue (kann einzelner Wert oder Liste sein)
If lookup.EditValue IsNot Nothing Then
Dim controlName As String = lookup.Name
lookupBackups(controlName) = lookup.EditValue
Logger.Debug($"GridTables_HandleControlValueChange -> Backup für Lookup [{controlName}]: [{lookup.EditValue}]")
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)
Logger.Error($"GridTables_HandleControlValueChange -> Fehler beim Backup von Lookup: {ex.Message}")
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
End If
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

View File

@@ -28,13 +28,31 @@ Namespace ControlCreator
Private _FormulaColumnNames As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
Private _isRefreshingFormula As Boolean = False ' *** NEU: Flag für Formel-Refresh ***
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)
_LogConfig = pLogConfig
_Logger = pLogConfig.GetLogger()
_GridTables = pGridTables
_currencySymbol = pCurrencySymbol
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
Dim oDataTable As New DataTable
Dim columnsWithExpressions As New List(Of Tuple(Of DataColumn, String))
@@ -202,15 +220,129 @@ Namespace ControlCreator
Return oEditor
End If
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)
Private Sub ApplyCurrencySummaryFormat(oCol As GridColumn)
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
' Variante A: Standard-Währungsformat aus aktueller Kultur
' oCol.SummaryItem.DisplayFormat = "SUM: {0:C2}"
_Logger.Debug("Applying currency summary format for column [{0}] with symbol [{1}]", oCol.FieldName, _currencySymbol)
' Variante B: Kulturunabhängig, Symbol explizit anhängen
oCol.SummaryItem.DisplayFormat = $"SUM: {{0:N2}} {_currencySymbol}"
oCol.SummaryItem.DisplayFormat = $"{{0:N2}} {_currencySymbol}"
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)
Dim oShouldDisplayFooter As Boolean = False
For Each oCol As GridColumn In pGridView.Columns
@@ -256,8 +388,13 @@ Namespace ControlCreator
oCol.DisplayFormat.FormatString = "N2"
Case "CURRENCY"
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = $"N2 {_currencySymbol}"
' *** DisplayFormat wird NICHT hier gesetzt ***
' 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
@@ -266,15 +403,16 @@ Namespace ControlCreator
Select Case oSummaryFunction
Case Constants.AGGREGATE_TOTAL_INTEGER
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N0}"
oCol.SummaryItem.DisplayFormat = "{0:N0}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_FLOAT
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N2}"
oCol.SummaryItem.DisplayFormat = "{0:N2}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_CURRENCY
_Logger.Debug(Of String)("Applying currency summary format for column [{0}]", oCol.FieldName)
ApplyCurrencySummaryFormat(oCol)
oShouldDisplayFooter = True
@@ -311,49 +449,140 @@ Namespace ControlCreator
End If
End Sub
Public Sub ConfigureViewColumnsCurrency(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl)
Dim oCultureInfo As CultureInfo = New CultureInfo("de-DE")
oCultureInfo.NumberFormat.CurrencySymbol = _currencySymbol
Dim riTextEdit As RepositoryItemTextEdit = New RepositoryItemTextEdit()
riTextEdit.MaskSettings.Configure(Of MaskSettings.Numeric)(Sub(settings)
settings.MaskExpression = "c"
settings.Culture = oCultureInfo
End Sub)
riTextEdit.UseMaskAsDisplayFormat = True
pGrid.RepositoryItems.Add(riTextEdit)
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}"
' *** 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
Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{oCol.FieldName}'").
FirstOrDefault()
If oColumnData Is Nothing Then Continue For
If oColumnData Is Nothing Then
Continue For
End If
Dim oColumnType As String = ObjectEx.NotNull(oColumnData.Item("TYPE_COLUMN"), String.Empty).ToString()
If oColumnType <> "CURRENCY" Then Continue For
' *** 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)
If oFormulaExpression <> String.Empty Then
_Logger.Debug("Skipping ColumnEdit assignment for formula column [{0}] using DisplayFormat only.", oCol.FieldName)
Continue For
Dim oIsFormula As Boolean = oFormulaExpression <> String.Empty
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
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
Case "CURRENCY"
' *** WICHTIG: NUR ColumnEdit setzen, KEIN DisplayFormat mehr! ***
oCol.ColumnEdit = riTextEdit
End Select
Next
If oColumnData IsNot Nothing AndAlso
oColumnData.Item("TYPE_COLUMN").ToString() = "CURRENCY" Then
Try
' *** KERN-FIX: Hole Symbol aus SHARED Dictionary statt Instanz-Feld ***
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
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
_FormulaColumnNames.Clear()
@@ -405,6 +634,15 @@ Namespace ControlCreator
oColumnData.Item("TYPE_COLUMN").ToString() = "CURRENCY" Then
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
' *** KRITISCH: Robustes Parsing unabhängig vom Dezimaltrenner ***
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)
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
_Logger.Warn("⚠️ Could not format currency value [{0}] for column [{1}]: {2}",
e.Value, e.Column.FieldName, ex.Message)
' 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 If
End Sub
@@ -442,19 +689,47 @@ Namespace ControlCreator
AddHandler pGridView.CustomRowCellEdit, Sub(sender As Object, e As CustomRowCellEditEventArgs)
Try
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)
If oColumnName <> e.Column.FieldName Then
Continue For
End If
If oEditorExists Then
' Combobox/Lookup-Editor aus GridTables: immer zuweisen
Dim oEditor = _GridTables.Item(pControlId).Item(oColumnName)
_Logger.Debug("Assigning Editor to Column [{0}]", oColumnName)
e.RepositoryItem = oEditor
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
Exit For
Next
Catch ex As Exception
_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:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("2.8.4.0")>
<Assembly: AssemblyVersion("2.8.5.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>
<Assembly: NeutralResourcesLanguage("")>

View File

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

View File

@@ -1,10 +1,11 @@
Imports System.Text.RegularExpressions
Imports WINDREAMLib
Imports DigitalData.Controls.LookupGrid
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Views.Grid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper
Imports DevExpress.XtraEditors
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraGrid.Views.Grid
Imports DigitalData.Controls.LookupGrid
Imports WINDREAMLib
''' <summary>
''' Defines common Functions for Checking for and replacing placeholders.
''' This Class also includes a child class `Pattern` for passing around Patterns.
@@ -150,34 +151,39 @@ Public Class clsPatterns
End Function
Public Shared Function ReplaceAllValues(input As String, panel As DevExpress.XtraEditors.XtraScrollableControl, is_SQL As Boolean) As String
Dim oResult = input
Try
Dim result = input
If Not HasAnyPatterns(result) Then
Return result
If Not HasAnyPatterns(oResult) Then
Return oResult
End If
LOGGER.Debug($"input BEFORE replacing: [{result}]")
result = ReplaceInternalValues(result)
LOGGER.Debug($"input BEFORE replacing: [{oResult}]")
oResult = ReplaceInternalValues(oResult)
If Not IsNothing(CURRENT_WMFILE) Then
result = ReplaceWindreamIndicies(result, CURRENT_WMFILE, is_SQL)
oResult = ReplaceWindreamIndicies(oResult, CURRENT_WMFILE, is_SQL)
End If
If IDB_ACTIVE = True Then
result = ReplaceIDBAttributes(result, is_SQL)
oResult = ReplaceIDBAttributes(oResult, is_SQL)
End If
'vorher hinter result = ReplaceInternalValues(result)
result = ReplaceControlValues(result, panel, is_SQL)
oResult = ReplaceControlValues(oResult, panel, is_SQL)
If Not IsNothing(result) Then
result = ReplaceUserValues(result)
LOGGER.Debug($"input AFTER replacing: [{result}]")
If Not IsNothing(oResult) Then
oResult = ReplaceUserValues(oResult)
LOGGER.Debug($"input AFTER replacing: [{oResult}]")
End If
Return result
Return oResult
Catch ex As Exception
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
End Try
End Function
@@ -354,12 +360,28 @@ Public Class clsPatterns
Case GetType(LookupControl3)
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
Else
oReplaceValue += "', '" + oString
@@ -367,13 +389,12 @@ Public Class clsPatterns
oIndex += 1
Next
oIsSQL = False
ElseIf oLookupControl3.Properties.SelectedValues.Count = 1 Then
LOGGER.Debug($"LookupControl3 mit genau einem Value")
oReplaceValue = oLookupControl3.Properties.SelectedValues(0)
Else
' LOGGER.Warn($"SelectedValues of LookUpControl scheint empty oder leer zu sein! Ersetzen mit ErrorReplaceValue!")
oReplaceValue = ERROR_REPLACE_VALUE
Else ' Count = 1
LOGGER.Debug($"LookupControl3 [{oControlName}] mit genau einem Value")
oReplaceValue = selectedValues(0)
End If
LOGGER.Debug($"oReplaceValue nach Durchlaufen selectedValues: {oReplaceValue}")
LOGGER.Debug($"oReplaceValue nach Durchlaufen selectedValues: {oReplaceValue}")
Case GetType(Windows.Forms.ComboBox)
@@ -381,7 +402,7 @@ Public Class clsPatterns
Case GetType(CheckBox)
Dim oCheckBox As CheckBox = oControl
oReplaceValue = oCheckBox.Checked
oReplaceValue = If(oCheckBox.Checked, "1", "0") ' Explizite String-Konvertierung
Case GetType(GridControl)
Dim oGrid As GridControl = oControl
@@ -406,10 +427,18 @@ Public Class clsPatterns
Case Else
oReplaceValue = ERROR_REPLACE_VALUE
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
'LOGGER.Debug($"IS_SQL = True - oReplaceValue = {oReplaceValue}")
'LOGGER.Debug($"oReplaceValue = {oReplaceValue}")
oReplaceValue = oReplaceValue.Replace("'", "''")
oReplaceValue = SafeSqlEscape(oReplaceValue)
End If
oResult = ReplacePattern(oResult, PATTERN_CTRL, oReplaceValue)
Else
@@ -425,16 +454,46 @@ Public Class clsPatterns
Return oResult
End Try
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
Try
Dim oResult = pInput
Dim oTryCounter As Integer = 0
While ContainsPattern(oResult, PATTERN_WMI)
Dim oWMValue As String
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
Throw New Exception("Max tries in ReplaceWindreamIndicies exceeded.")

View File

@@ -125,7 +125,7 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADw
CAAAAk1TRnQBSQFMAgEBAgEAAfABCwHwAQsBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
CAAAAk1TRnQBSQFMAgEBAgEAAfgBCwH4AQsBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
@@ -1506,13 +1506,13 @@
<value>Aktionen</value>
</data>
<data name="RibbonControl1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 158</value>
<value>1178, 126</value>
</data>
<data name="RibbonStatusBar1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 666</value>
<value>0, 670</value>
</data>
<data name="RibbonStatusBar1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 22</value>
<value>1178, 18</value>
</data>
<data name="&gt;&gt;RibbonStatusBar1.Name" xml:space="preserve">
<value>RibbonStatusBar1</value>
@@ -1539,7 +1539,7 @@
<value>4</value>
</data>
<data name="GridControlWorkflows.Size" type="System.Drawing.Size, System.Drawing">
<value>945, 484</value>
<value>945, 549</value>
</data>
<data name="GridControlWorkflows.TabIndex" type="System.Int32, mscorlib">
<value>10</value>
@@ -1782,7 +1782,7 @@
<value>233</value>
</data>
<data name="NavBarControl1.Size" type="System.Drawing.Size, System.Drawing">
<value>233, 508</value>
<value>233, 573</value>
</data>
<data name="NavBarControl1.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
@@ -1809,10 +1809,10 @@
<value>Tahoma, 9pt</value>
</data>
<data name="Panel1.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 158</value>
<value>0, 101</value>
</data>
<data name="Panel1.Size" type="System.Drawing.Size, System.Drawing">
<value>1178, 508</value>
<value>1178, 573</value>
</data>
<data name="Panel1.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
@@ -2111,7 +2111,7 @@
<value>9, 19</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>1178, 688</value>
<value>1473, 860</value>
</data>
<data name="$this.Font" type="System.Drawing.Font, System.Drawing">
<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
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
' Prüfen ob das Formular im sichtbaren Bereich liegt
EnsureFormIsVisible()
formLoaded = True
End Sub