2 Commits

Author SHA1 Message Date
Developer01
540f9bcc12 Aktualisierung, Speichern und Leeren von GridControl-Zellen 2026-06-19 10:36:36 +02:00
Developer01
e2016e4214 Vor Übernahme 2026-06-18 17:23:36 +02:00
2 changed files with 321 additions and 54 deletions

View File

@@ -143,6 +143,13 @@
<Component Id="GDPictureLibs" Guid="9ea5ab43-58ff-4813-9a8b-f854784f0275">
<File Id="GdPicture.NET.14" Name="GdPicture.NET.14.dll" KeyPath="yes" />
<File Id="GdPicture.NET.14.barcode.1d.reader.64" Name="GdPicture.NET.14.barcode.1d.reader.64.dll" />
<File Id="GdPicture.NET.14.barcode.1d.reader" Name="GdPicture.NET.14.barcode.1d.reader.dll" />
<File Id="GdPicture.NET.14.barcode.1d.writer" Name="GdPicture.NET.14.barcode.1d.writer.dll" />
<File Id="GdPicture.NET.14.barcode.2d.reader.64" Name="GdPicture.NET.14.barcode.2d.reader.64.dll" />
<File Id="GdPicture.NET.14.barcode.2d.reader" Name="GdPicture.NET.14.barcode.2d.reader.dll" />
<File Id="GdPicture.NET.14.barcode.2d.writer" Name="GdPicture.NET.14.barcode.2d.writer.dll" />
<File Id="GdPicture.NET.14.WinForms" Name="GdPicture.NET.14.WinForms.dll" />
<File Id="GdPicture.NET.14.CAD" Name="GdPicture.NET.14.CAD.dll" />
<File Id="GdPicture.NET.14.CAD.DWG" Name="GdPicture.NET.14.CAD.DWG.dll" />
<File Id="GdPicture.NET.14.filters" Name="GdPicture.NET.14.filters.dll" />
@@ -157,6 +164,9 @@
<File Id="GdPicture.NET.14.Imaging.ML.64" Name="GdPicture.NET.14.Imaging.ML.64.dll" />
<File Id="GdPicture.NET.14.Imaging.ML" Name="GdPicture.NET.14.Imaging.ML.dll" />
<File Id="GdPicture.NET.14.Imaging.Formats.Conversion" Name="GdPicture.NET.14.Imaging.Formats.Conversion.dll" />
<File Id="GdPicture.NET.14.machine.vision.64" Name="GdPicture.NET.14.machine.vision.64.dll" />
<File Id="GdPicture.NET.14.machine.vision" Name="GdPicture.NET.14.machine.vision.dll" />
<File Id="GdPicture.NET.14.Markdown" Name="GdPicture.NET.14.Markdown.dll" />
<File Id="GdPicture.NET.14.Common" Name="GdPicture.NET.14.Common.dll" />
<File Id="GdPicture.NET.14.Document" Name="GdPicture.NET.14.Document.dll" />
<File Id="GdPicture.NET.14.PDF" Name="GdPicture.NET.14.PDF.dll" />
@@ -170,22 +180,142 @@
<File Id="BouncyCastle.Cryptography" Name="BouncyCastle.Cryptography.dll"/>
<File Id="DocumentFormat.OpenXml" Name="DocumentFormat.OpenXml.dll" />
<File Id="DocumentFormat.OpenXml.Framework" Name="DocumentFormat.OpenXml.Framework.dll" />
<File Id="GdPicture.NET.14.OpenXML.Templating" Name="GdPicture.NET.14.OpenXML.Templating.dll" />
<File Id="GdPicture.NET.14.twain.client.64" Name="GdPicture.NET.14.twain.client.64.dll" />
<File Id="GdPicture.NET.14.twain.client" Name="GdPicture.NET.14.twain.client.dll" />
<File Id="Microsoft.Bcl.AsyncInterfaces" Name="Microsoft.Bcl.AsyncInterfaces.dll" />
<File Id="Microsoft.Bcl.Cryptography" Name="Microsoft.Bcl.Cryptography.dll" />
<File Id="Microsoft.Bcl.HashCode" Name="Microsoft.Bcl.HashCode.dll" />
<File Id="Microsoft.Identity.Client" Name="Microsoft.Identity.Client.dll" />
<File Id="Microsoft.IdentityModel.Abstractions" Name="Microsoft.IdentityModel.Abstractions.dll" />
<File Id="Microsoft.Win32.Primitives" Name="Microsoft.Win32.Primitives.dll" />
<File Id="Microsoft.Win32.Registry" Name="Microsoft.Win32.Registry.dll" />
<File Id="OpenMcdf" Name="OpenMcdf.dll" />
<File Id="netstandard" Name="netstandard.dll" />
<File Id="Newtonsoft.Json.Bson" Name="Newtonsoft.Json.Bson.dll" />
<File Id="Google.Protobuf" Name="Google.Protobuf.dll" />
<File Id="protobufnet.Core" Name="protobuf-net.Core.dll" />
<File Id="protobufnet" Name="protobuf-net.dll" />
<File Id="RtfPipe" Name="RtfPipe.dll" />
<File Id="System.AppContext" Name="System.AppContext.dll" />
<File Id="System.Buffers" Name="System.Buffers.dll" />
<File Id="System.CodeDom" Name="System.CodeDom.dll" />
<File Id="System.Collections.Concurrent" Name="System.Collections.Concurrent.dll" />
<File Id="System.Collections" Name="System.Collections.dll" />
<File Id="System.Collections.Immutable" Name="System.Collections.Immutable.dll" />
<File Id="System.Collections.NonGeneric" Name="System.Collections.NonGeneric.dll" />
<File Id="System.Collections.Specialized" Name="System.Collections.Specialized.dll" />
<File Id="System.ComponentModel.EventBasedAsync" Name="System.ComponentModel.EventBasedAsync.dll" />
<File Id="System.ComponentModel.Primitives" Name="System.ComponentModel.Primitives.dll" />
<File Id="System.ComponentModel" Name="System.ComponentModel.dll" />
<File Id="System.ComponentModel.TypeConverter" Name="System.ComponentModel.TypeConverter.dll" />
<File Id="System.Console" Name="System.Console.dll" />
<File Id="System.Data.Common" Name="System.Data.Common.dll" />
<File Id="System.Data.Odbc" Name="System.Data.Odbc.dll" />
<File Id="System.Diagnostics.Contracts" Name="System.Diagnostics.Contracts.dll" />
<File Id="System.Diagnostics.Debug" Name="System.Diagnostics.Debug.dll" />
<File Id="System.Diagnostics.FileVersionInfo" Name="System.Diagnostics.FileVersionInfo.dll" />
<File Id="System.Diagnostics.Process" Name="System.Diagnostics.Process.dll" />
<File Id="System.Diagnostics.StackTrace" Name="System.Diagnostics.StackTrace.dll" />
<File Id="System.Diagnostics.TextWriterTraceListener" Name="System.Diagnostics.TextWriterTraceListener.dll" />
<File Id="System.Diagnostics.Tools" Name="System.Diagnostics.Tools.dll" />
<File Id="System.Diagnostics.TraceSource" Name="System.Diagnostics.TraceSource.dll" />
<File Id="System.Diagnostics.Tracing" Name="System.Diagnostics.Tracing.dll" />
<File Id="System.Drawing.Primitives" Name="System.Drawing.Primitives.dll" />
<File Id="System.Dynamic.Runtime" Name="System.Dynamic.Runtime.dll" />
<File Id="System.Formats.Asn1" Name="System.Formats.Asn1.dll" />
<File Id="System.Globalization.Calendars" Name="System.Globalization.Calendars.dll" />
<File Id="System.Globalization" Name="System.Globalization.dll" />
<File Id="System.Globalization.Extensions" Name="System.Globalization.Extensions.dll" />
<File Id="System.IO.Compression" Name="System.IO.Compression.dll" />
<File Id="System.IO.Compression.ZipFile" Name="System.IO.Compression.ZipFile.dll" />
<File Id="System.IO" Name="System.IO.dll" />
<File Id="System.IO.FileSystem" Name="System.IO.FileSystem.dll" />
<File Id="System.IO.FileSystem.DriveInfo" Name="System.IO.FileSystem.DriveInfo.dll" />
<File Id="System.IO.FileSystem.Primitives" Name="System.IO.FileSystem.Primitives.dll" />
<File Id="System.IO.FileSystem.Watcher" Name="System.IO.FileSystem.Watcher.dll" />
<File Id="System.IO.IsolatedStorage" Name="System.IO.IsolatedStorage.dll" />
<File Id="System.IO.MemoryMappedFiles" Name="System.IO.MemoryMappedFiles.dll" />
<File Id="System.IO.Pipelines" Name="System.IO.Pipelines.dll" />
<File Id="System.IO.Pipes" Name="System.IO.Pipes.dll" />
<File Id="System.IO.UnmanagedMemoryStream" Name="System.IO.UnmanagedMemoryStream.dll" />
<File Id="System.Linq" Name="System.Linq.dll" />
<File Id="System.Linq.Expressions" Name="System.Linq.Expressions.dll" />
<File Id="System.Linq.Parallel" Name="System.Linq.Parallel.dll" />
<File Id="System.Linq.Queryable" Name="System.Linq.Queryable.dll" />
<File Id="System.Memory2" Name="System.Memory.dll" />
<File Id="System.Net.Http" Name="System.Net.Http.dll" />
<File Id="System.Net.Http.Formatting" Name="System.Net.Http.Formatting.dll" />
<File Id="System.Net.NameResolution" Name="System.Net.NameResolution.dll" />
<File Id="System.Net.NetworkInformation" Name="System.Net.NetworkInformation.dll" />
<File Id="System.Net.Ping" Name="System.Net.Ping.dll" />
<File Id="System.Net.Primitives" Name="System.Net.Primitives.dll" />
<File Id="System.Net.Requests" Name="System.Net.Requests.dll" />
<File Id="System.Net.Security" Name="System.Net.Security.dll" />
<File Id="System.Net.Sockets" Name="System.Net.Sockets.dll" />
<File Id="System.Net.WebHeaderCollection" Name="System.Net.WebHeaderCollection.dll" />
<File Id="System.Net.WebSockets.Client" Name="System.Net.WebSockets.Client.dll" />
<File Id="System.Net.WebSockets" Name="System.Net.WebSockets.dll" />
<File Id="System.Numerics.Vectors.xml" Name="System.Numerics.Vectors.xml" />
<File Id="System.ObjectModel" Name="System.ObjectModel.dll" />
<File Id="System.Reflection" Name="System.Reflection.dll" />
<File Id="System.Reflection.Extensions" Name="System.Reflection.Extensions.dll" />
<File Id="System.Reflection.Primitives" Name="System.Reflection.Primitives.dll" />
<File Id="System.Resources.Reader" Name="System.Resources.Reader.dll" />
<File Id="System.Resources.ResourceManager" Name="System.Resources.ResourceManager.dll" />
<File Id="System.Resources.Writer" Name="System.Resources.Writer.dll" />
<File Id="System.Runtime.CompilerServices.Unsafe.xml" Name="System.Runtime.CompilerServices.Unsafe.xml" />
<File Id="System.Runtime.CompilerServices.VisualC" Name="System.Runtime.CompilerServices.VisualC.dll" />
<File Id="System.Runtime" Name="System.Runtime.dll" />
<File Id="System.Runtime.Extensions" Name="System.Runtime.Extensions.dll" />
<File Id="System.Runtime.Handles" Name="System.Runtime.Handles.dll" />
<File Id="System.Runtime.InteropServices" Name="System.Runtime.InteropServices.dll" />
<File Id="System.Runtime.InteropServices.RuntimeInformation" Name="System.Runtime.InteropServices.RuntimeInformation.dll" />
<File Id="System.Runtime.Numerics" Name="System.Runtime.Numerics.dll" />
<File Id="System.Runtime.Serialization.Formatters" Name="System.Runtime.Serialization.Formatters.dll" />
<File Id="System.Runtime.Serialization.Json" Name="System.Runtime.Serialization.Json.dll" />
<File Id="System.Runtime.Serialization.Primitives" Name="System.Runtime.Serialization.Primitives.dll" />
<File Id="System.Runtime.Serialization.Xml" Name="System.Runtime.Serialization.Xml.dll" />
<File Id="System.Security.Claims" Name="System.Security.Claims.dll" />
<File Id="System.Security.Cryptography.Algorithms" Name="System.Security.Cryptography.Algorithms.dll" />
<File Id="System.Security.Cryptography.Csp" Name="System.Security.Cryptography.Csp.dll" />
<File Id="System.Security.Cryptography.Encoding" Name="System.Security.Cryptography.Encoding.dll" />
<File Id="System.Security.Cryptography.Pkcs.xml" Name="System.Security.Cryptography.Pkcs.xml" />
<File Id="System.Security.Cryptography.Primitives" Name="System.Security.Cryptography.Primitives.dll" />
<File Id="System.Security.Cryptography.X509Certificates" Name="System.Security.Cryptography.X509Certificates.dll" />
<File Id="System.Security.Principal" Name="System.Security.Principal.dll" />
<File Id="System.Security.SecureString" Name="System.Security.SecureString.dll" />
<File Id="System.Text.Encoding" Name="System.Text.Encoding.dll" />
<File Id="System.Text.Encoding.Extensions" Name="System.Text.Encoding.Extensions.dll" />
<File Id="System.Text.Encodings.Web.xml" Name="System.Text.Encodings.Web.xml" />
<File Id="System.Text.Json.xml" Name="System.Text.Json.xml" />
<File Id="System.Text.RegularExpressions" Name="System.Text.RegularExpressions.dll" />
<File Id="System.Threading.Channels" Name="System.Threading.Channels.dll" />
<File Id="System.Threading.Channels.xml" Name="System.Threading.Channels.xml" />
<File Id="System.Threading" Name="System.Threading.dll" />
<File Id="System.Threading.Overlapped" Name="System.Threading.Overlapped.dll" />
<File Id="System.Threading.Tasks" Name="System.Threading.Tasks.dll" />
<File Id="System.Threading.Tasks.Extensions.xml" Name="System.Threading.Tasks.Extensions.xml" />
<File Id="System.Threading.Tasks.Parallel" Name="System.Threading.Tasks.Parallel.dll" />
<File Id="System.IO.Packaging" Name="System.IO.Packaging.dll" />
<File Id="System.Memory" Name="System.Memory.dll" />
<File Id="System.Numerics.Vectors" Name="System.Numerics.Vectors.dll" />
<File Id="System.Threading.Thread" Name="System.Threading.Thread.dll" />
<File Id="System.Threading.ThreadPool" Name="System.Threading.ThreadPool.dll" />
<File Id="System.Threading.Timer" Name="System.Threading.Timer.dll" />
<File Id="System.ValueTuple.xml" Name="System.ValueTuple.xml" />
<File Id="System.Xml.ReaderWriter" Name="System.Xml.ReaderWriter.dll" />
<File Id="System.Xml.XDocument" Name="System.Xml.XDocument.dll" />
<File Id="System.Xml.XmlDocument" Name="System.Xml.XmlDocument.dll" />
<File Id="System.Xml.XmlSerializer" Name="System.Xml.XmlSerializer.dll" />
<File Id="System.Xml.XPath" Name="System.Xml.XPath.dll" />
<File Id="System.Xml.XPath.XDocument" Name="System.Xml.XPath.XDocument.dll" />
<File Id="System.Runtime.CompilerServices.Unsafe" Name="System.Runtime.CompilerServices.Unsafe.dll" />
<File Id="System.Security.Cryptography.Pkcs" Name="System.Security.Cryptography.Pkcs.dll" />
<File Id="System.Text.Encodings.Web" Name="System.Text.Encodings.Web.dll" />
<File Id="System.Threading.Tasks.Extensions" Name="System.Threading.Tasks.Extensions.dll" />
<File Id="System.ValueTuple" Name="System.ValueTuple.dll" />
<File Id="NativeSDK.Settings" Name="NativeSDK.Settings.dll" />
<File Id="NativeSDK.Settings.Edition" Name="NativeSDK.Settings.Edition.dll" />
<File Id="NativeSDK.Exceptions" Name="NativeSDK.Exceptions.dll" />
</Component>
<Component Id="DevExpressLibs" Guid="CB40DAAE-348E-4BD3-B275-9A526EB8F191">

View File

@@ -33,6 +33,7 @@ Namespace ControlCreator
Private Shared _ResolvedSqlCache As New Dictionary(Of String, String)
Private _isRefreshingFormula As Boolean = False ' *** NEU: Flag für Formel-Refresh ***
Private _clearOperationsInProgress As New HashSet(Of String) ' Format: "GridViewHashCode|ColumnName"
Private _currencySymbol As String = ""
''' <summary>
''' SHARED Dictionary: Speichert das aktuelle Währungssymbol PRO GridView (via Name).
@@ -90,26 +91,38 @@ Namespace ControlCreator
For Each match As Match In matches
Dim colName = match.Groups(1).Value
Dim cellValue = pView.GetRowCellValue(rowHandle, colName)
Dim safeValue As String = ConvertToSqlValue(cellValue) ' Hilfsfunktion
Dim safeValue As String = ConvertToSqlValue(cellValue)
resolvedSql = resolvedSql.Replace(match.Value, safeValue)
Next
' *** SCHRITT 2: {#CTRL#...} via clsPatterns - MIT CACHE ***
If _ParentControl IsNot Nothing AndAlso resolvedSql.Contains("{#CTRL#") Then
' Cache-Key: Hash aus SQL + Control-Werten
Dim cacheKey = GenerateCacheKey(resolvedSql, _ParentControl)
' *** FIX: Cache-Key ERST NACH ReplaceAllValues erstellen! ***
Dim beforeReplace = resolvedSql
resolvedSql = clsPatterns.ReplaceAllValues(resolvedSql, _ParentControl, True)
' *** JETZT Cache-Key erstellen (mit aufgelösten Control-Werten) ***
Dim cacheKey = resolvedSql.GetHashCode().ToString()
SyncLock _ResolvedSqlCache
If _ResolvedSqlCache.ContainsKey(cacheKey) Then
resolvedSql = _ResolvedSqlCache(cacheKey)
' Kein Log → spart 200+ Zeilen
Else
' Nur bei Cache-Miss ReplaceAllValues aufrufen
resolvedSql = clsPatterns.ReplaceAllValues(resolvedSql, _ParentControl, True)
' Cache speichern (für nächsten Aufruf)
If Not _ResolvedSqlCache.ContainsKey(cacheKey) Then
_ResolvedSqlCache(cacheKey) = resolvedSql
If LOG_HOTSPOTS Then _Logger.Debug("[ResolveSqlTemplate] ReplaceAllValues-Cache MISS")
_Logger.Debug("[ResolveSqlTemplate] ✓ Cached SQL: Key=[{0}]", cacheKey)
End If
End SyncLock
' *** DEBUG: Log VOR/NACH (nur beim ersten Aufruf) ***
If LOG_HOTSPOTS Then
_Logger.Info("[ResolveSqlTemplate] BEFORE: {0}",
beforeReplace.Substring(0, Math.Min(150, beforeReplace.Length)))
_Logger.Info("[ResolveSqlTemplate] AFTER: {0}",
resolvedSql.Substring(0, Math.Min(150, resolvedSql.Length)))
End If
Else
If _ParentControl Is Nothing Then
_Logger.Warn("[ResolveSqlTemplate] _ParentControl is NOTHING! Cannot replace {{#CTRL#...}}")
End If
End If
Return resolvedSql
@@ -134,6 +147,27 @@ Namespace ControlCreator
End If
End Function
''' <summary>
''' Durchsucht rekursiv alle Child-Controls nach einem bestimmten Namen.
''' Notwendig, weil Controls.Find() in TableLayoutPanels/GroupBoxen manchmal versagt.
''' </summary>
Private Function FindControlRecursive(parent As Control, controlName As String) As Control
If parent Is Nothing Then Return Nothing
For Each child As Control In parent.Controls
If child.Name = controlName Then
Return child
End If
' Rekursiv in Kindern suchen
If child.HasChildren Then
Dim found = FindControlRecursive(child, controlName)
If found IsNot Nothing Then Return found
End If
Next
Return Nothing
End Function
''' <summary>
''' Placeholder für Control-Value-Hashing.
''' </summary>
Private Function GenerateCacheKey(sql As String, parent As Control) As String
@@ -784,7 +818,7 @@ Namespace ControlCreator
AddHandler pGridView.CustomRowCellEdit,
Sub(sender As Object, e As CustomRowCellEditEventArgs)
Try
' *** NEU: Dynamische Editoren aus Cache oder neu erstellen ***
' *** SCHRITT 1: Dynamische Editoren ZUERST prüfen ***
If _DynamicEditorColumns.Contains(e.Column.FieldName) Then
Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{e.Column.FieldName}'").
@@ -795,38 +829,52 @@ Namespace ControlCreator
Dim oConnectionId As Integer = oColumnData.ItemEx("CONNECTION_ID", 1)
Dim oIsAdvancedLookup As Boolean = oColumnData.ItemEx("ADVANCED_LOOKUP", False)
' *** SQL auflösen (für Cache-Key) ***
Dim resolvedSql = ResolveSqlTemplate(oSqlCommand, TryCast(sender, GridView), e.RowHandle)
If String.IsNullOrEmpty(oSqlCommand) Then
_Logger.Warn("⚠️ [CustomRowCellEdit] Column [{0}] has no SQL_COMMAND!", e.Column.FieldName)
Return
End If
' *** CACHE-KEY: Spaltenname + aufgelöstes SQL (HashCode) ***
' *** NEU: ResolveSqlTemplate HIER aufrufen! ***
Dim resolvedSql As String = ResolveSqlTemplate(oSqlCommand, DirectCast(sender, GridView), e.RowHandle)
' Cache-Key basiert auf RESOLVED SQL
Dim cacheKey As String = $"{e.Column.FieldName}|{resolvedSql.GetHashCode()}"
' *** CACHE-CHECK ***
' Cache prüfen
SyncLock _DynamicEditorCacheShared
If _DynamicEditorCacheShared.ContainsKey(cacheKey) Then
' ✅ CACHE HIT: Editor wiederverwenden
_Logger.Info("[CustomRowCellEdit] ✓ CACHE HIT: [{0}]", cacheKey)
e.RepositoryItem = _DynamicEditorCacheShared(cacheKey)
Else
' ❌ CACHE MISS: Neuen Editor erstellen
Return
End If
End SyncLock
' Editor erstellen mit RESOLVED SQL
_Logger.Info("[CustomRowCellEdit] 🆕 MISS: Creating editor for [{0}]", e.Column.FieldName)
Dim realEditor = CreateRowSpecificEditor(e.Column.FieldName, resolvedSql, oConnectionId, oIsAdvancedLookup)
Dim realEditor = CreateRowSpecificEditor(
e.Column.FieldName,
resolvedSql,
oConnectionId,
oIsAdvancedLookup,
DirectCast(sender, GridView),
e.RowHandle
)
If realEditor IsNot Nothing Then
' *** IN CACHE SPEICHERN ***
_DynamicEditorCacheShared(cacheKey) = realEditor
e.RepositoryItem = realEditor
SyncLock _DynamicEditorCacheShared
If Not _DynamicEditorCacheShared.ContainsKey(cacheKey) Then
_DynamicEditorCacheShared.Add(cacheKey, realEditor)
End If
End SyncLock
_Logger.Info("[CustomRowCellEdit] ✓ Cached [{0}] editor (Type=[{1}])", e.Column.FieldName, realEditor.GetType().Name)
e.RepositoryItem = realEditor
Else
_Logger.Warn("[CustomRowCellEdit] CreateRowSpecificEditor returned Nothing for [{0}]", e.Column.FieldName)
End If
End If
End SyncLock
End If
Return
Return ' ✅ WICHTIG: Verlässt Handler nach dynamischem Editor!
End If
' Standard-Editor aus Cache
' *** SCHRITT 2: Statische Editoren (nur wenn NICHT dynamisch) ***
Dim oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, e.Column.FieldName)
If oEditorExists Then
_Logger.Debug("[CustomRowCellEdit] Assigning RepositoryItem for column [{0}] from GridTables cache.", e.Column.FieldName)
@@ -996,6 +1044,91 @@ Namespace ControlCreator
End If
End Sub
AddHandler pGridView.ShownEditor,
Sub(sender As Object, e As EventArgs)
Try
Dim view As GridView = TryCast(sender, GridView)
If view Is Nothing OrElse view.ActiveEditor Is Nothing Then Return
' Nur für LookupControl3
Dim activeEditor = TryCast(view.ActiveEditor, LookupControl3)
If activeEditor Is Nothing Then Return
' Nur für dynamische Editoren
Dim columnName = view.FocusedColumn?.FieldName
If String.IsNullOrEmpty(columnName) OrElse Not _DynamicEditorColumns.Contains(columnName) Then Return
' Verhindere doppelte Registrierung via Tag
If activeEditor.Tag IsNot Nothing AndAlso activeEditor.Tag.ToString() = "ClearHandlerRegistered" Then
_Logger.Debug("[ShownEditor] Properties.SelectedValuesChanged-Handler bereits registriert für [{0}]", columnName)
Return
End If
_Logger.Debug("[ShownEditor] ✓ Registriere Properties.SelectedValuesChanged-Handler für [{0}]", columnName)
' *** Properties.SelectedValuesChanged mit GLOBALEM Guard ***
Dim clearHandler As RepositoryItemLookupControl3.SelectedValuesChangedHandler =
Sub(editorSender As Object, selectedValues As List(Of String))
Try
Dim isCleared As Boolean = selectedValues Is Nothing OrElse selectedValues.Count = 0
If isCleared Then
' *** GLOBALES GUARD: Key aus GridView-Hash + ColumnName ***
Dim guardKey As String = $"{view.GetHashCode()}|{columnName}"
SyncLock _clearOperationsInProgress
If _clearOperationsInProgress.Contains(guardKey) Then
_Logger.Debug("[LookupControl3] Clear already in progress for [{0}] → SKIP", columnName)
Return
End If
' Guard aktivieren
_clearOperationsInProgress.Add(guardKey)
End SyncLock
_Logger.Info("[LookupControl3] Properties.SelectedValuesChanged leer → clearing [{0}]", columnName)
' BeginInvoke: Lookup ERST schließen lassen, DANN Zelle leeren
view.GridControl.BeginInvoke(New Action(
Sub()
Try
Dim rowHandle = view.FocusedRowHandle
If view.IsValidRowHandle(rowHandle) Then
view.SetRowCellValue(rowHandle, columnName, String.Empty)
_Logger.Debug("[LookupControl3] ✓ Cell cleared: Row={0}, Column={1}", rowHandle, columnName)
End If
Catch ex As Exception
_Logger.Error("[LookupControl3] Error in BeginInvoke: {0}", ex.Message)
_Logger.Error(ex)
Finally
' *** GUARD ZURÜCKSETZEN (nach UI-Update) ***
SyncLock _clearOperationsInProgress
_clearOperationsInProgress.Remove(guardKey)
End SyncLock
End Try
End Sub))
Else
_Logger.Debug("[LookupControl3] Properties.SelectedValuesChanged.Count=[{0}] → keine Löschung", selectedValues.Count)
End If
Catch ex As Exception
_Logger.Error("[LookupControl3] Properties.SelectedValuesChanged Error: {0}", ex.Message)
_Logger.Error(ex)
End Try
End Sub
' Handler registrieren
AddHandler activeEditor.Properties.SelectedValuesChanged, clearHandler
' Markierung setzen (verhindert doppelte Registrierung)
activeEditor.Tag = "ClearHandlerRegistered"
Catch ex As Exception
_Logger.Error("[ShownEditor] Properties.SelectedValuesChanged-Handler Error: {0}", ex.Message)
_Logger.Error(ex)
End Try
End Sub
AddHandler pGridView.ValidateRow, AddressOf View_ValidateRow
AddHandler pControl.LostFocus, AddressOf Control_LostFocus
@@ -1332,7 +1465,10 @@ CheckNewItemRow:
columnName As String,
resolvedSql As String,
connectionId As Integer,
isAdvancedLookup As Boolean) As RepositoryItem
isAdvancedLookup As Boolean,
pView As GridView, ' ← NEU!
pRowHandle As Integer ' ← NEU!
) As RepositoryItem
Try
If LOG_HOTSPOTS Then _Logger.Debug("[CreateRowSpecificEditor] Executing SQL for column [{0}]: {1}", columnName, resolvedSql)
@@ -1349,12 +1485,7 @@ CheckNewItemRow:
Return Nothing
End If
If LOG_HOTSPOTS Then _Logger.Debug("[CreateRowSpecificEditor] Retrieved {0} rows for column [{1}]", oDataTable.Rows.Count, columnName)
' *** NEU: Log erste 5 Rows für Debugging ***
For i As Integer = 0 To Math.Min(4, oDataTable.Rows.Count - 1)
If LOG_HOTSPOTS Then _Logger.Debug("[CreateRowSpecificEditor] DataTable Row[{0}]: [{1}]", i, oDataTable.Rows(i)(0))
Next
LOGGER.Debug("[CreateRowSpecificEditor] Retrieved {0} rows for column [{1}]", oDataTable.Rows.Count, columnName)
' Editor erstellen (analog zu GridTables_GetRepositoryItemForColumn)
If isAdvancedLookup Then
@@ -1549,12 +1680,22 @@ CheckNewItemRow:
If pView Is Nothing OrElse pArgs Is Nothing OrElse pArgs.Column Is Nothing Then
Return
End If
' *** NEU: Bei Formel-Refresh überspringen ***
If _isRefreshingFormula Then
_Logger.Debug("Skipping HandleInheritedColumnValue during formula refresh.")
Return
End If
' *** NEU: Guard-Prüfung für btnClear-Operationen ***
Dim guardKey As String = $"{pView.GetHashCode()}|{pArgs.Column.FieldName}"
SyncLock _clearOperationsInProgress
If _clearOperationsInProgress.Contains(guardKey) Then
_Logger.Debug("[HandleInheritedColumnValue] Clear operation in progress for [{0}] → SKIP inheritance dialog", pArgs.Column.FieldName)
Return
End If
End SyncLock
If isApplyingInheritedValue OrElse pArgs.RowHandle = DevExpress.XtraGrid.GridControl.InvalidRowHandle Then
If isApplyingInheritedValue Then
_Logger.Debug("Currently applying inherited value for column {0} skipping to prevent recursion.", pArgs.Column.FieldName)
@@ -1596,7 +1737,7 @@ CheckNewItemRow:
Dim affectedRowsCount = pView.DataRowCount - listIndex - 1
Dim confirmationEntry = GetInheritanceConfirmationEntry(pArgs.Column.FieldName)
_Logger.Debug("Inheritance confirmation entry for column {0}: {1}", pArgs.Column.FieldName, confirmationEntry.Count)
If affectedRowsCount > 0 AndAlso confirmationEntry.Count < InheritanceMsgAmount Then
Dim confirmMessage As String = String.Format(
"Möchten Sie den Wert '{0}' an {1} nachfolgende Zeile(n) vererben?",
@@ -1689,7 +1830,6 @@ CheckNewItemRow:
pView.SetRowCellValue(targetHandle, pArgs.Column.FieldName, valueToApply)
' *** SCHRITT 2: Cache-Keys für DIESE Zeile sammeln ***
' Finde alle dynamischen Spalten, die die geänderte Spalte via {#TBCOL#...} referenzieren
For Each dynColName In _DynamicEditorColumns
Dim oColDef As DataRow = pColumnDefinition.
Select($"SPALTENNAME = '{dynColName}'").
@@ -1699,9 +1839,7 @@ CheckNewItemRow:
Dim oSqlCommand As String = oColDef.ItemEx("SQL_COMMAND", "")
' Prüfe ob SQL {#TBCOL#<ColumnName>} enthält
If oSqlCommand.Contains($"{{#TBCOL#{pArgs.Column.FieldName}}}") Then
' SQL auflösen mit NEUEM Wert (targetHandle!)
Try
Dim resolvedSql = ResolveSqlTemplate(oSqlCommand, pView, targetHandle)
Dim cacheKey = $"{dynColName}|{resolvedSql.GetHashCode()}"
@@ -1740,7 +1878,6 @@ CheckNewItemRow:
isApplyingInheritedValue = False
End Try
End Sub
Private Sub SetInheritanceConfirmationCount(columnName As String, newCount As Integer)
Dim entries = UserInheritance_ConfirmationByColumn
If entries Is Nothing Then