Neue Funktionalität für dynamische Editoren: - Einführung eines Shared-Caches (`_DynamicEditorCacheShared`) zur Wiederverwendung von Editoren in `GridControl`. - Dynamische Editoren werden nun pro Zeile behandelt und bei Bedarf aus dem Cache geladen oder neu erstellt. - Neue Methode `ClearDynamicEditorCache`, um den Cache bei Dokumentwechsel zu leeren. Optimierung der Ereignisbehandlung: - Überarbeitung des `CustomRowCellEdit`-Events für effizientere Zuweisung dynamischer Editoren. - Vereinfachung der Logik für `ShowingEditor` und Entfernung veralteter Logik für `HiddenEditor`. Erweiterte Debugging-Optionen: - Einführung des Flags `LOG_HOTSPOTS`, um gezielt Debugging-Informationen zu aktivieren. - Verbesserte Logs für SQL-Abfragen, Cache-Zugriffe und Editor-Erstellungen. Code-Bereinigung und Stabilität: - Entfernung redundanter Logik und Vereinfachung der Behandlung von Währungsformaten. - Verbesserte Speicherverwaltung durch explizites Entfernen und Disposen von Editoren. - Zusätzliche Sicherheitsprüfungen und Fehlerbehandlungen. Ziel der Änderungen: Verbesserung der Performance durch Caching, Erhöhung der Stabilität durch erweiterte Fehlerbehandlung und Optimierung der Wartbarkeit durch klarere Logs und vereinfachte Logik.
1111 lines
47 KiB
VB.net
1111 lines
47 KiB
VB.net
Imports System.ComponentModel
|
|
Imports System.Text.RegularExpressions
|
|
Imports DevExpress.Utils
|
|
Imports DevExpress.XtraEditors
|
|
Imports DevExpress.XtraEditors.Controls
|
|
Imports DevExpress.XtraEditors.NavigatorButtons
|
|
Imports DevExpress.XtraEditors.Repository
|
|
Imports DevExpress.XtraGrid
|
|
Imports DevExpress.XtraGrid.Columns
|
|
Imports DevExpress.XtraGrid.Views.Base
|
|
Imports DevExpress.XtraGrid.Views.Grid
|
|
Imports DigitalData.Controls.LookupGrid
|
|
Imports DigitalData.GUIs.Common
|
|
Imports DigitalData.Modules.Logging
|
|
Imports DigitalData.Modules.EDMI.API.DatabaseWithFallback
|
|
Imports DigitalData.Modules.EDMI.API.Constants
|
|
Imports DigitalData.Modules.Base
|
|
|
|
Public Class ClassControlCreator
|
|
|
|
''' <summary>
|
|
''' Konstanten
|
|
''' </summary>
|
|
Private Const DEFAULT_TEXT = "Bezeichnung definieren"
|
|
|
|
Private Const DEFAULT_FONT_SIZE As Integer = 10
|
|
Private Const DEFAULT_FONT_FAMILY As String = "Arial"
|
|
Private Const DEFAULT_FONT_STYLE As FontStyle = FontStyle.Regular
|
|
Private Const DEFAULT_COLOR As Integer = 0
|
|
Private Const DEFAULT_WIDTH As Integer = 170
|
|
Private Const DEFAULT_HEIGHT As Integer = 20
|
|
Private Const DEFAULT_HEIGHT_TABLE As Integer = 150
|
|
|
|
Public Const PREFIX_TEXTBOX = "TXT"
|
|
Public Const PREFIX_LABEL = "LBL"
|
|
Public Const PREFIX_CHECKBOX = "CHK"
|
|
Public Const PREFIX_COMBOBOX = "CMB"
|
|
Public Const PREFIX_DATETIMEPICKER = "DTP"
|
|
Public Const PREFIX_DATAGRIDVIEW = "DGV"
|
|
Public Const PREFIX_LOOKUP = "LU"
|
|
Public Const PREFIX_TABLE = "TB"
|
|
Public Const PREFIX_LINE = "LINE"
|
|
Public Const PREFIX_BUTTON = "BTN"
|
|
|
|
Public Const AGGREGATE_NONE = "NONE"
|
|
Public Const AGGREGATE_TOTAL_INTEGER = "TOTAL_INTEGER"
|
|
Public Const AGGREGATE_TOTAL_FLOAT = "TOTAL_FLOAT"
|
|
Public Const AGGREGATE_TOTAL_CURRENCY = "TOTAL_CURRENCY"
|
|
Public Const AGGREGATE_TOTAL_MIN = "TOTAL_MIN"
|
|
Public Const AGGREGATE_TOTAL_MAX = "TOTAL_MAX"
|
|
Public Const AGGREGATE_TOTAL_AVG = "TOTAL_AVG"
|
|
Public Const AGGREGATE_TOTAL_COUNT = "TOTAL_COUNT"
|
|
|
|
Public Const CONTROL_TYPE_TEXT = "TEXT"
|
|
Public Const CONTROL_TYPE_INTEGER = "INTEGER"
|
|
Public Const CONTROL_TYPE_BOOLEAN = "BOOLEAN"
|
|
Public Const CONTROL_TYPE_DOUBLE = "DOUBLE"
|
|
Public Const CONTROL_TYPE_CURRENCY = "CURRENCY"
|
|
Public Const CONTROL_TYPE_DATE = "DATE"
|
|
Public Const CONTROL_TYPE_DATETIME = "DATETIME"
|
|
|
|
|
|
Public ReadOnly Property Logger As Logger
|
|
Public ReadOnly Property LogConfig As LogConfig
|
|
|
|
''' <summary>
|
|
''' Saves the column data for each grid and each column in that grid
|
|
''' </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>
|
|
''' Standard Eigenschaften für alle Controls
|
|
''' </summary>
|
|
Private Class ControlDBProps
|
|
Public Guid As Integer
|
|
Public Name As String
|
|
Public Attribute As String
|
|
Public Location As Point
|
|
Public [Font] As Font
|
|
Public [Color] As Color
|
|
Public [ReadOnly] As Boolean
|
|
Public AddNewItems As Boolean = False
|
|
End Class
|
|
|
|
Public Class ControlMetadata
|
|
Public Guid As Integer
|
|
Public Name As String
|
|
Public Attribute As String
|
|
Public [ReadOnly] As Boolean = False
|
|
Public BackColor As Color = Color.White
|
|
Public Property IsDirty As Boolean = False
|
|
End Class
|
|
|
|
Public Sub New(pLogConfig As LogConfig)
|
|
LogConfig = pLogConfig
|
|
Logger = pLogConfig.GetLogger()
|
|
End Sub
|
|
|
|
Private Function TransformDataRow(row As DataRow) As ControlDBProps
|
|
Dim x As Integer = row.Item("X_LOC")
|
|
Dim y As Integer = row.Item("Y_LOC")
|
|
Dim style As FontStyle = ClassAllgemeineFunktionen.NotNullString(row.Item("FONT_STYLE"), DEFAULT_FONT_STYLE)
|
|
Dim size As Single = ClassAllgemeineFunktionen.NotNullString(row.Item("FONT_SIZE"), DEFAULT_FONT_SIZE)
|
|
Dim familyString As String = ClassAllgemeineFunktionen.NotNullString(row.Item("FONT_FAMILY"), DEFAULT_FONT_FAMILY)
|
|
Dim family As FontFamily = New FontFamily(familyString)
|
|
|
|
Dim oGuid As Integer = row.Item("GUID")
|
|
Dim oControlName As String = ClassAllgemeineFunktionen.NotNullString(row.Item("NAME"), "")
|
|
Dim oAttribute As String = ClassAllgemeineFunktionen.NotNullString(row.Item("INDEX_NAME"), "")
|
|
Dim oLocation As New Point(x, y)
|
|
Dim oFont As New Font(family, size, style, GraphicsUnit.Point)
|
|
Dim oColor As Color = IntToColor(ClassAllgemeineFunktionen.NotNullString(row.Item("FONT_COLOR"), DEFAULT_COLOR))
|
|
Dim oReadOnly As Boolean = row.Item("READ_ONLY")
|
|
Dim oAddNewItems As Boolean = row.Item("VKT_ADD_ITEM")
|
|
If oAttribute = "@@DISPLAY_ONLY" And oReadOnly = False Then
|
|
Logger.Info($"Override oReadOnly = True for Control [{oControlName}] as Attribute is @@DISPLAY_ONLY and ReadOnly = False")
|
|
oReadOnly = True
|
|
End If
|
|
|
|
Return New ControlDBProps() With {
|
|
.Guid = oGuid,
|
|
.Name = oControlName,
|
|
.Attribute = oAttribute,
|
|
.Location = oLocation,
|
|
.Font = oFont,
|
|
.Color = oColor,
|
|
.ReadOnly = oReadOnly,
|
|
.AddNewItems = oAddNewItems
|
|
}
|
|
End Function
|
|
|
|
Public Function CreateBaseControl(ctrl As Control, OControlRow As DataRow, designMode As Boolean) As Control
|
|
Try
|
|
Dim props As ControlDBProps = TransformDataRow(OControlRow)
|
|
|
|
ctrl.Tag = New ControlMetadata() With {
|
|
.Guid = props.Guid,
|
|
.Attribute = props.Attribute,
|
|
.ReadOnly = props.ReadOnly,
|
|
.Name = props.Name
|
|
}
|
|
ctrl.Name = props.Name
|
|
ctrl.Location = props.Location
|
|
ctrl.Font = props.Font
|
|
ctrl.ForeColor = props.Color
|
|
If designMode Then
|
|
ctrl.Cursor = Cursors.Hand
|
|
End If
|
|
|
|
If props.ReadOnly Then
|
|
ctrl.BackColor = Color.LightGray
|
|
End If
|
|
|
|
Return ctrl
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Return Nothing
|
|
End Try
|
|
|
|
End Function
|
|
|
|
' ----------------------- NEW CONTROLS -----------------------
|
|
|
|
Public Function CreateNewTextBox(location As Point) As TextEdit
|
|
Dim control As New TextEdit With {
|
|
.Name = $"{PREFIX_TEXTBOX}_{ClassAllgemeineFunktionen.NewShortGuid()}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
|
.Location = location,
|
|
.ReadOnly = True,
|
|
.BackColor = Color.White,
|
|
.Cursor = Cursors.Hand
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewLabel(location As Point) As Label
|
|
Dim control As New Label With {
|
|
.Name = $"{PREFIX_LABEL}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Text = DEFAULT_TEXT,
|
|
.AutoSize = True,
|
|
.Location = location,
|
|
.Cursor = Cursors.Hand
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewCheckbox(location As Point) As CheckBox
|
|
Dim control As New CheckBox With {
|
|
.Name = $"{PREFIX_CHECKBOX}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.AutoSize = True,
|
|
.Text = DEFAULT_TEXT,
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location,
|
|
.CheckState = CheckState.Indeterminate
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewCombobox(location As Point) As Windows.Forms.ComboBox
|
|
Dim control As New Windows.Forms.ComboBox With {
|
|
.Name = $"{PREFIX_COMBOBOX}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewDatetimepicker(location As Point) As DateTimePicker
|
|
Dim control As New DateTimePicker With {
|
|
.Name = $"{PREFIX_DATETIMEPICKER}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location,
|
|
.Format = DateTimePickerFormat.Short
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewDatagridview(location As Point) As DataGridView
|
|
Dim control As New DataGridView With {
|
|
.Name = $"{PREFIX_DATAGRIDVIEW}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT_TABLE),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location,
|
|
.AllowUserToAddRows = False,
|
|
.AllowUserToDeleteRows = False,
|
|
.AllowUserToResizeColumns = False,
|
|
.AllowUserToResizeRows = False
|
|
}
|
|
|
|
control.Columns.Add(New DataGridViewTextBoxColumn With {
|
|
.HeaderText = "",
|
|
.Name = "column1"
|
|
})
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Friend Function CreateNewLookupControl(location As Point) As LookupControl3
|
|
Dim control As New LookupControl3 With {
|
|
.Name = $"{PREFIX_LOOKUP}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location
|
|
}
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateNewTable(location As Point) As GridControl
|
|
Dim oControl As New GridControl With {
|
|
.Name = $"{PREFIX_TABLE}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT_TABLE),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location,
|
|
.UseEmbeddedNavigator = True
|
|
}
|
|
oControl.ForceInitialize()
|
|
Dim oView As GridView = oControl.DefaultView
|
|
oView.OptionsView.ShowGroupPanel = False
|
|
|
|
Dim oDatatable As New DataTable()
|
|
oDatatable.Columns.Add("column1", GetType(String))
|
|
oDatatable.Columns.Add("column2", GetType(String))
|
|
oControl.DataSource = oDatatable
|
|
|
|
Return oControl
|
|
End Function
|
|
|
|
Public Function CreateNewLine(location As Point) As LineLabel
|
|
Dim control As New LineLabel With {
|
|
.Name = $"{PREFIX_LINE}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Text = "---------------------------------",
|
|
.Size = New Size(100, 5),
|
|
.Location = location
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
Public Function CreateNewButton(location As Point) As Button
|
|
Dim control As New Button With {
|
|
.Name = $"{PREFIX_BUTTON}_{ClassAllgemeineFunktionen.NewShortGuid}",
|
|
.Size = New Size(108, 28),
|
|
.Cursor = Cursors.Hand,
|
|
.Location = location
|
|
}
|
|
|
|
Return control
|
|
End Function
|
|
|
|
' ----------------------- EXISITING CONTROLS -----------------------
|
|
|
|
Public Function CreateExistingTextbox(oControlRow As DataRow, designMode As Boolean) As BaseEdit
|
|
Try
|
|
Dim oHeight = oControlRow.ItemEx("HEIGHT", 0)
|
|
Dim oWidth = oControlRow.ItemEx("WIDTH", 0)
|
|
Dim oReadOnly = oControlRow.ItemEx("READ_ONLY", False)
|
|
Dim oFormatString = oControlRow.ItemEx("FORMAT_STRING", String.Empty)
|
|
Dim oBackColorIf = oControlRow.ItemEx("CTRL_BACKCOLOR_IF", String.Empty)
|
|
Dim oIndexname = oControlRow.ItemEx("INDEX_NAME", String.Empty)
|
|
Dim oAlignment = oControlRow.ItemEx("TEXT_ALIGNMENT", "Near")
|
|
Dim oControl As BaseEdit = Nothing
|
|
If oHeight >= 27 Then
|
|
oControl = CreateBaseControl(New MemoEdit(), oControlRow, designMode)
|
|
Else
|
|
oControl = CreateBaseControl(New TextEdit(), oControlRow, designMode)
|
|
End If
|
|
|
|
Dim oMeta As ControlMetadata = oControl.Tag
|
|
|
|
oControl.BackColor = Color.White
|
|
oMeta.BackColor = Color.White
|
|
|
|
oControl.Height = oHeight
|
|
oControl.Width = oWidth
|
|
If oAlignment = "Near" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Near
|
|
ElseIf oAlignment = "Center" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center
|
|
ElseIf oAlignment = "Far" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far
|
|
End If
|
|
|
|
If Not designMode Then
|
|
oControl.ReadOnly = oReadOnly
|
|
oControl.TabStop = Not oReadOnly
|
|
oControl.BackColor = IIf(oReadOnly, Color.LightGray, Color.White)
|
|
|
|
' If there is a format string defined, set it for display only.
|
|
' Editing will be without format string, according to current user-culture.
|
|
If oFormatString <> String.Empty Then
|
|
oControl.Properties.DisplayFormat.FormatType = FormatType.Custom
|
|
oControl.Properties.DisplayFormat.FormatString = ClassFormat.GetFormatString(oFormatString)
|
|
'ElseIf oReadOnly Then
|
|
' ' For read only controls, don't show the raw value when a user clicks into it
|
|
' oControl.Properties.EditFormat.FormatType = FormatType.Custom
|
|
' oControl.Properties.EditFormat.FormatString = ClassFormat.GetFormatString(oFormatString)
|
|
End If
|
|
Else
|
|
oControl.ReadOnly = True
|
|
End If
|
|
|
|
Return oControl
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Return Nothing
|
|
End Try
|
|
End Function
|
|
|
|
Public Function CreateExistingLabel(row As DataRow, designMode As Boolean) As Label
|
|
Dim oControl As Label = CreateBaseControl(New Label(), row, designMode)
|
|
Try
|
|
oControl.Text = row.Item("CTRL_CAPTION_LANG")
|
|
Catch ex As Exception
|
|
Logger.Warn("⚠️ Label [{0}] does not have a translation!", oControl.Name)
|
|
oControl.Text = row.Item("CTRL_TEXT")
|
|
End Try
|
|
Dim oAlignment = row.ItemEx("TEXT_ALIGNMENT", "Near")
|
|
If oAlignment = "Near" Then
|
|
oControl.TextAlign = ContentAlignment.MiddleLeft
|
|
ElseIf oAlignment = "Center" Then
|
|
oControl.TextAlign = ContentAlignment.MiddleCenter
|
|
ElseIf oAlignment = "Far" Then
|
|
oControl.TextAlign = ContentAlignment.MiddleRight
|
|
End If
|
|
oControl.AutoSize = True
|
|
|
|
Return oControl
|
|
End Function
|
|
|
|
Public Function CreateExistingButton(row As DataRow, designMode As Boolean) As Button
|
|
Dim oControl As Button = CreateBaseControl(New Button(), row, designMode)
|
|
|
|
Dim ctrl_image As Bitmap = Nothing
|
|
Dim oBitmap As Bitmap
|
|
If Not IsDBNull(row.Item("IMAGE_CONTROL")) Then
|
|
Dim obimg() As Byte = row.Item("IMAGE_CONTROL")
|
|
oBitmap = ByteArrayToBitmap(obimg)
|
|
ctrl_image = oBitmap
|
|
End If
|
|
|
|
Try
|
|
oControl.Text = row.Item("CTRL_CAPTION_LANG")
|
|
Catch ex As Exception
|
|
oControl.Text = row.Item("CTRL_TEXT")
|
|
End Try
|
|
|
|
oControl.Height = row.Item("HEIGHT")
|
|
oControl.Width = row.Item("WIDTH")
|
|
|
|
If Not IsNothing(ctrl_image) And Not IsNothing(oBitmap) Then
|
|
oControl.Image = oBitmap
|
|
oControl.ImageAlign = ContentAlignment.MiddleLeft
|
|
oControl.TextAlign = ContentAlignment.MiddleRight
|
|
End If
|
|
oControl.AutoSize = True
|
|
|
|
Return oControl
|
|
End Function
|
|
Public Function CreateExistingCombobox(pRow As DataRow, designMode As Boolean) As Windows.Forms.ComboBox
|
|
Dim oControl As Windows.Forms.ComboBox = CreateBaseControl(New Windows.Forms.ComboBox(), pRow, designMode)
|
|
oControl.Size = New Size(pRow.Item("WIDTH"), pRow.Item("HEIGHT"))
|
|
|
|
If Not designMode Then
|
|
oControl.Enabled = Not pRow.Item("READ_ONLY")
|
|
oControl.TabStop = Not pRow.Item("READ_ONLY")
|
|
oControl.BackColor = IIf(pRow.Item("READ_ONLY"), Color.LightGray, Color.White)
|
|
|
|
oControl.AutoCompleteMode = AutoCompleteMode.SuggestAppend
|
|
oControl.AutoCompleteSource = AutoCompleteSource.ListItems
|
|
End If
|
|
|
|
'' Apply text alignment by owner-drawing based on oAlignment
|
|
'Dim oAlignment = pRow.ItemEx("TEXT_ALIGNMENT", "Near")
|
|
|
|
'' Ensure owner-draw so we can control text alignment
|
|
'oControl.DrawMode = Global.System.Windows.Forms.DrawMode.OwnerDrawFixed
|
|
|
|
'' Attach handler with inline drawing logic respecting alignment
|
|
'AddHandler oControl.DrawItem,
|
|
'Sub(sender As Object, e As DrawItemEventArgs)
|
|
' Dim cmb = TryCast(sender, Windows.Forms.ComboBox)
|
|
' If cmb Is Nothing Then Return
|
|
' e.DrawBackground()
|
|
' If e.Index >= 0 AndAlso e.Index < cmb.Items.Count Then
|
|
' Dim text As String = cmb.GetItemText(cmb.Items(e.Index))
|
|
' Dim sf As New StringFormat(StringFormatFlags.NoWrap)
|
|
' Select Case oAlignment
|
|
' Case "Near"
|
|
' sf.Alignment = StringAlignment.Near
|
|
' Case "Center"
|
|
' sf.Alignment = StringAlignment.Center
|
|
' Case "Far"
|
|
' sf.Alignment = StringAlignment.Far
|
|
' Case Else
|
|
' sf.Alignment = StringAlignment.Near
|
|
' End Select
|
|
' sf.LineAlignment = StringAlignment.Center
|
|
' Using foreBrush As New SolidBrush(If((e.State And DrawItemState.Selected) = DrawItemState.Selected, SystemColors.HighlightText, cmb.ForeColor))
|
|
' e.Graphics.DrawString(text, e.Font, foreBrush, e.Bounds, sf)
|
|
' End Using
|
|
' End If
|
|
' e.DrawFocusRectangle()
|
|
'End Sub
|
|
|
|
Return oControl
|
|
End Function
|
|
|
|
Public Function CreateExistingDatepicker(row As DataRow, designMode As Boolean) As DateTimePicker
|
|
Dim control As DateTimePicker = CreateBaseControl(New DateTimePicker(), row, designMode)
|
|
|
|
control.Size = New Size(row.Item("WIDTH"), row.Item("HEIGHT"))
|
|
control.Format = DateTimePickerFormat.Short
|
|
|
|
If Not designMode Then
|
|
control.Enabled = Not row.Item("READ_ONLY")
|
|
control.TabStop = Not row.Item("READ_ONLY")
|
|
End If
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateExisingCheckbox(row As DataRow, designMode As Boolean) As CheckBox
|
|
Dim oCheckBox As CheckBox = CreateBaseControl(New CheckBox(), row, designMode)
|
|
|
|
oCheckBox.AutoSize = True
|
|
Try
|
|
oCheckBox.Text = row.Item("CTRL_CAPTION_LANG")
|
|
Catch ex As Exception
|
|
oCheckBox.Text = row.Item("CTRL_TEXT")
|
|
End Try
|
|
oCheckBox.CheckState = CheckState.Indeterminate
|
|
|
|
If Not designMode Then
|
|
oCheckBox.Enabled = Not row.Item("READ_ONLY")
|
|
oCheckBox.TabStop = Not row.Item("READ_ONLY")
|
|
End If
|
|
|
|
Return oCheckBox
|
|
End Function
|
|
|
|
Public Function CreateExistingDataGridView(row As DataRow, designMode As Boolean) As DataGridView
|
|
Dim control As DataGridView = CreateBaseControl(New DataGridView(), row, designMode)
|
|
|
|
control.Size = New Size(row.Item("WIDTH"), row.Item("HEIGHT"))
|
|
control.AllowUserToAddRows = False
|
|
control.AllowUserToDeleteRows = False
|
|
control.AllowUserToResizeColumns = False
|
|
control.AllowUserToResizeRows = False
|
|
control.AlternatingRowsDefaultCellStyle.BackColor = Color.Aqua
|
|
|
|
Dim col As New DataGridViewTextBoxColumn
|
|
col.HeaderText = ""
|
|
col.Name = "column1"
|
|
col.Width = control.Width - 30
|
|
control.Columns.Add(col)
|
|
|
|
If Not designMode Then
|
|
control.Enabled = Not row.Item("READ_ONLY")
|
|
control.TabStop = Not row.Item("READ_ONLY")
|
|
End If
|
|
|
|
Return control
|
|
End Function
|
|
|
|
Public Function CreateExistingLookupControl(pRow As DataRow, pDesignMode As Boolean) As LookupControl3
|
|
Dim oControl As LookupControl3 = CreateBaseControl(New LookupControl3(), pRow, pDesignMode)
|
|
oControl.Properties.Name = oControl.Name
|
|
oControl.Width = pRow.Item("WIDTH")
|
|
oControl.ReadOnly = pRow.Item("READ_ONLY")
|
|
oControl.Properties.AllowAddNewValues = pRow.Item("VKT_ADD_ITEM")
|
|
Dim oAlignment = pRow.ItemEx("TEXT_ALIGNMENT", "Near")
|
|
|
|
If oAlignment = "Near" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Near
|
|
ElseIf oAlignment = "Center" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center
|
|
ElseIf oAlignment = "Far" Then
|
|
oControl.Properties.Appearance.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far
|
|
End If
|
|
|
|
If pDesignMode Then
|
|
oControl.Cursor = Cursors.Hand
|
|
End If
|
|
|
|
Return oControl
|
|
End Function
|
|
|
|
Public Function CreateExistingGridControl(row As DataRow, DT_MY_COLUMNS As DataTable, designMode As Boolean,
|
|
pcurrencySymbol As String, pParentControl As Control) As GridControl
|
|
Dim oGridControlCreator = New ControlCreator.GridControl(LogConfig, GridTables, pcurrencySymbol, pParentControl)
|
|
Dim oControl As GridControl = CreateBaseControl(New GridControl(), row, designMode)
|
|
Dim oControlId = DirectCast(oControl.Tag, ControlMetadata).Guid
|
|
Dim oView As GridView
|
|
Dim oControlName = oControl.Name
|
|
oControl.ForceInitialize()
|
|
|
|
oView = oControl.MainView
|
|
oView.OptionsView.ShowGroupPanel = False
|
|
oControl.ContextMenu = Nothing
|
|
|
|
Dim oGridBuilder As New GridBuilder(oView)
|
|
oGridBuilder.WithClipboardHandler()
|
|
|
|
If Not designMode Then
|
|
oView.OptionsBehavior.Editable = Not row.Item("READ_ONLY")
|
|
oView.OptionsBehavior.ReadOnly = row.Item("READ_ONLY")
|
|
'oView.OptionsBehavior.EditorShowMode = EditorShowMode.Click
|
|
If oView.OptionsBehavior.ReadOnly = True Then
|
|
oView.OptionsBehavior.Editable = False
|
|
End If
|
|
oControl.UseEmbeddedNavigator = Not row.Item("READ_ONLY")
|
|
|
|
oView.OptionsBehavior.EditorShowMode = EditorShowMode.MouseDown
|
|
|
|
' Copy single cell value in CTRL+C instead of whole row
|
|
oView.OptionsSelection.MultiSelectMode = GridMultiSelectMode.CellSelect
|
|
oView.OptionsSelection.MultiSelect = True
|
|
oView.OptionsClipboard.CopyColumnHeaders = DefaultBoolean.False
|
|
'oView.OptionsView.ColumnAutoWidth = True
|
|
If oView.OptionsBehavior.ReadOnly = False Then
|
|
If row.Item("VKT_ADD_ITEM") = True Then
|
|
oView.OptionsBehavior.AllowAddRows = DefaultBoolean.True
|
|
oView.OptionsBehavior.AllowDeleteRows = DefaultBoolean.True
|
|
oView.OptionsView.NewItemRowPosition = NewItemRowPosition.Bottom
|
|
Else
|
|
oView.OptionsBehavior.Editable = False
|
|
oView.OptionsView.NewItemRowPosition = NewItemRowPosition.None
|
|
End If
|
|
End If
|
|
|
|
End If
|
|
|
|
oControl.Size = New Size(row.Item("WIDTH"), row.Item("HEIGHT"))
|
|
' Add and configure navigator to delete rows
|
|
oControl.UseEmbeddedNavigator = True
|
|
With oControl.EmbeddedNavigator.Buttons
|
|
.CancelEdit.Visible = False
|
|
.Edit.Visible = False
|
|
.EndEdit.Visible = False
|
|
.First.Visible = False
|
|
.Last.Visible = False
|
|
.Next.Visible = False
|
|
.NextPage.Visible = False
|
|
.PrevPage.Visible = False
|
|
.Prev.Visible = False
|
|
|
|
End With
|
|
|
|
If GridColumns.ContainsKey(oControlId) Then
|
|
GridColumns.Item(oControlId) = DT_MY_COLUMNS
|
|
Else
|
|
GridColumns.Add(oControlId, DT_MY_COLUMNS)
|
|
End If
|
|
|
|
If GridTables.ContainsKey(oControlId) Then
|
|
GridTables.Item(oControlId).Clear()
|
|
Else
|
|
GridTables.Add(oControlId, New Dictionary(Of String, RepositoryItem)())
|
|
End If
|
|
|
|
Dim oDataTable = oGridControlCreator.CreateGridColumns(DT_MY_COLUMNS)
|
|
GridTables = oGridControlCreator.FillGridTables(DT_MY_COLUMNS, oControlId, oControl.Name)
|
|
oView.PopulateColumns(oDataTable)
|
|
oControl.DataSource = oDataTable
|
|
oControl.RefreshDataSource()
|
|
oControl.ForceInitialize()
|
|
|
|
|
|
If row.Item("TABLE_ORDER_COLUMN") <> String.Empty Then
|
|
Try
|
|
Dim oSortTerm = row.Item("TABLE_ORDER_COLUMN").ToString
|
|
Dim oSortOrder As DevExpress.Data.ColumnSortOrder = DevExpress.Data.ColumnSortOrder.Ascending
|
|
If oSortTerm.Contains(" ASC") Then
|
|
oSortTerm = oSortTerm.Replace(" ASC", "")
|
|
ElseIf oSortTerm.Contains(" DESC") Then
|
|
oSortOrder = DevExpress.Data.ColumnSortOrder.Descending
|
|
oSortTerm = oSortTerm.Replace(" DESC", "")
|
|
End If
|
|
oView.BeginDataUpdate()
|
|
Try
|
|
oView.ClearSorting()
|
|
oView.Columns(oSortTerm).SortOrder = oSortOrder
|
|
Finally
|
|
oView.EndDataUpdate()
|
|
End Try
|
|
Catch ex As Exception
|
|
|
|
End Try
|
|
End If
|
|
|
|
' *** KORRIGIERT: ConfigureViewColumns OHNE currencySymbol-Parameter ***
|
|
oGridControlCreator.ConfigureViewColumns(DT_MY_COLUMNS, oView, oControl)
|
|
|
|
' *** NEU: ConfigureViewColumnsCurrency() für editierbare Währungsspalten ***
|
|
oGridControlCreator.ConfigureViewColumnsCurrency(DT_MY_COLUMNS, oView, oControl)
|
|
|
|
oGridControlCreator.ConfigureViewEvents(DT_MY_COLUMNS, oView, oControl, oControlId)
|
|
oView.FocusInvalidRow()
|
|
|
|
Return oControl
|
|
End Function
|
|
|
|
Private newRowModified As Boolean = False
|
|
|
|
|
|
|
|
Public Function CreateExistingLine(row As DataRow, designMode As Boolean) As LineLabel
|
|
Dim control As LineLabel = CreateBaseControl(New LineLabel(), row, designMode)
|
|
control.Text = "------------------------------"
|
|
control.BorderStyle = BorderStyle.None
|
|
control.AutoSize = False
|
|
control.BackColor = IntToColor(ClassAllgemeineFunktionen.NotNullString(row.Item("FONT_COLOR"), DEFAULT_COLOR))
|
|
control.Size = New Size(row.Item("WIDTH"), row.Item("HEIGHT"))
|
|
|
|
Return control
|
|
End Function
|
|
|
|
|
|
' ----------------------- CUSTOM LABEL/LINE CLASS -----------------------
|
|
|
|
Public Class LineLabel
|
|
Inherits Label
|
|
|
|
Protected Overrides Sub OnPaint(e As PaintEventArgs)
|
|
'MyBase.OnPaint(e)
|
|
|
|
Dim size As New Size(e.ClipRectangle.Width, 2)
|
|
Dim rect As New Rectangle(New Point(0, 0), size)
|
|
|
|
'ControlPaint.DrawBorder(e.Graphics, rect, Me.ForeColor, ButtonBorderStyle.Solid)
|
|
e.Graphics.DrawLine(New Pen(ForeColor, 100), New Point(0, 0), New Point(e.ClipRectangle.Width, 2))
|
|
End Sub
|
|
End Class
|
|
|
|
Public Function GET_CONTROL_PROPERTIES(DT_CONTROL As DataTable, ControlName As String)
|
|
Try
|
|
CURRENT_CONTROL_ID = 0
|
|
CURR_CON_ID = 0
|
|
CURR_SELECT_CONTROL = ""
|
|
CURR_CHOICE_LIST = ""
|
|
Dim dt As New DataTable
|
|
dt = DT_CONTROL
|
|
' Define the filter
|
|
Dim filter As String = "NAME = '" & ControlName & "'"
|
|
' Filter the rows using Select() method of DataTable
|
|
Dim FilteredRows As DataRow() = dt.Select(filter)
|
|
If FilteredRows.Count = 1 Then
|
|
For Each row As DataRow In FilteredRows
|
|
CURRENT_CONTROL_ID = row("GUID")
|
|
CURR_CON_ID = IIf(IsDBNull(row("CONNECTION_ID")), 0, row("CONNECTION_ID"))
|
|
If CURR_CON_ID = 0 Then
|
|
Logger.Info("CONNECTION NOT DEFINED - CTRL_GUID:" & CURRENT_CONTROL_ID)
|
|
End If
|
|
|
|
CURR_SELECT_CONTROL = IIf(IsDBNull(row("SQL_UEBERPRUEFUNG")), "", row("SQL_UEBERPRUEFUNG"))
|
|
CURR_CHOICE_LIST = IIf(IsDBNull(row("CHOICE_LIST")), "", row("CHOICE_LIST"))
|
|
Next
|
|
Return 1
|
|
Else
|
|
Return 0
|
|
End If
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Logger.Info("Unexpected Error in GET_CONTROL_PROPERTIES (" & ControlName & "):" & ex.Message)
|
|
Return 0
|
|
End Try
|
|
|
|
End Function
|
|
Public Function GET_CONTROL_PROPERTY(DT_CONTROL As DataTable, ControlGUID As Integer, ColNAME As String)
|
|
Try
|
|
CURRENT_CONTROL_ID = 0
|
|
CURR_CON_ID = 0
|
|
CURR_SELECT_CONTROL = ""
|
|
CURR_CHOICE_LIST = ""
|
|
Dim dt As New DataTable
|
|
dt = DT_CONTROL
|
|
' Define the filter
|
|
Dim filter As String = "GUID = " & ControlGUID
|
|
' Filter the rows using Select() method of DataTable
|
|
Dim FilteredRows As DataRow() = dt.Select(filter)
|
|
If FilteredRows.Count = 1 Then
|
|
Dim oRESULT = FilteredRows(0).Item(ColNAME)
|
|
If IsDBNull(oRESULT) Then Return Nothing
|
|
|
|
Return oRESULT
|
|
Else
|
|
Return Nothing
|
|
End If
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Logger.Info("Unexpected Error in GET_CONTROL_PROPERTY (" & ControlGUID & "#" & ColNAME & "):" & ex.Message)
|
|
Return Nothing
|
|
End Try
|
|
|
|
End Function
|
|
|
|
Public Function GetDependingControls(DT_CONTROLS As DataTable, ControlName As String) As Boolean
|
|
Try
|
|
Dim dt As New DataTable
|
|
dt = DT_CONTROLS
|
|
' Define the filter
|
|
Dim filter As String = String.Format("SQL_UEBERPRUEFUNG LIKE '%{0}%'", ControlName)
|
|
Dim FilteredRows As DataRow() = dt.Select(filter)
|
|
CURR_DT_DEPENDING_CONTROLS = Nothing
|
|
If FilteredRows.Length > 0 Then
|
|
CURR_DT_DEPENDING_CONTROLS = FilteredRows.CopyToDataTable
|
|
End If
|
|
|
|
Return True
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Logger.Info("Unexpected Error in GET_DEPENDING_CONTROLS (" & ControlName & "):" & ex.Message)
|
|
Return False
|
|
End Try
|
|
End Function
|
|
|
|
Public Function GET_CONNECTION_INFO(CON_ID As Integer) As DataRow()
|
|
Try
|
|
Dim dt As New DataTable
|
|
dt = BASEDATA_DT_TBDD_CONNECTION
|
|
' Define the filter
|
|
Dim filter As String = "GUID = " & CON_ID
|
|
' Filter the rows using Select() method of DataTable
|
|
Dim FilteredRows As DataRow() = dt.Select(filter)
|
|
If FilteredRows.Count = 1 Then
|
|
Return FilteredRows
|
|
Else
|
|
Return Nothing
|
|
End If
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
Logger.Info("Unexpected Error in GET_CONNECTION_INFO (" & CON_ID.ToString & "):" & ex.Message)
|
|
Return Nothing
|
|
End Try
|
|
End Function
|
|
|
|
Public Sub GridTables_CacheDatatableForColumn(pControlId As Object, pColumnName As Object, pSqlStatement As Object, pConnectionId As Integer, pAdvancedLookup As Boolean)
|
|
Try
|
|
'Dim oTable As DataTable = ClassDatabase.Return_Datatable_ConId(pSqlStatement, pConnectionId)
|
|
Dim oTable As DataTable = DatabaseFallback.GetDatatable(New GetDatatableOptions(pSqlStatement, DatabaseType.ECM) With {
|
|
.ConnectionId = pConnectionId
|
|
})
|
|
|
|
' If no columns for this control have been added, create an empty dict now
|
|
If Not GridTables.ContainsKey(pControlId) Then
|
|
GridTables.Add(pControlId, New Dictionary(Of String, RepositoryItem))
|
|
End If
|
|
|
|
Dim oRepositoryItem = GridTables_GetRepositoryItemForColumn(pColumnName, oTable, pAdvancedLookup)
|
|
Dim oColumnDictionary = GridTables.Item(pControlId)
|
|
|
|
If oColumnDictionary.ContainsKey(pColumnName) Then
|
|
oColumnDictionary.Item(pColumnName) = oRepositoryItem
|
|
Else
|
|
oColumnDictionary.Add(pColumnName, oRepositoryItem)
|
|
End If
|
|
Catch ex As Exception
|
|
Logger.Error(ex)
|
|
End Try
|
|
End Sub
|
|
|
|
Public Function GridTables_GetRepositoryItemForColumn(pColumnName As String, pDataTable As DataTable, pIsAdvancedLookup As Boolean) As RepositoryItem
|
|
If pIsAdvancedLookup Then
|
|
|
|
Dim oEditor = New RepositoryItemLookupControl3
|
|
|
|
If pDataTable IsNot Nothing Then
|
|
oEditor.DisplayMember = pDataTable.Columns.Item(0).ColumnName
|
|
oEditor.ValueMember = pDataTable.Columns.Item(0).ColumnName
|
|
oEditor.DataSource = pDataTable
|
|
End If
|
|
|
|
Return oEditor
|
|
Else
|
|
Dim oEditor = New RepositoryItemComboBox()
|
|
Dim oItems As New List(Of String)
|
|
|
|
AddHandler oEditor.Validating, Sub(_sender As ComboBoxEdit, _e As CancelEventArgs)
|
|
If oItems.Contains(_sender.EditValue) Then
|
|
_e.Cancel = False
|
|
Else
|
|
_e.Cancel = True
|
|
End If
|
|
|
|
End Sub
|
|
|
|
If pDataTable IsNot Nothing Then
|
|
For Each oRow2 As DataRow In pDataTable.Rows
|
|
Dim oValue = oRow2.Item(0)
|
|
|
|
Try
|
|
If oRow2.ItemArray.Length > 1 Then
|
|
oValue &= $" | {oRow2.Item(1)}"
|
|
End If
|
|
Catch ex As Exception
|
|
End Try
|
|
|
|
oEditor.Items.Add(oValue)
|
|
oItems.Add(oValue)
|
|
Next
|
|
End If
|
|
|
|
Return oEditor
|
|
End If
|
|
End Function
|
|
|
|
Public Sub GridTables_HandleControlValueChange(pControlPanel As XtraScrollableControl, pColumnsWithSqlAndControlPlaceholders As DataTable)
|
|
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 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($"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")
|
|
|
|
' *** NEU: Prüfe ob Spalte #TBCOL# verwendet (dynamisch pro Zeile) ***
|
|
If oSqlStatement <> String.Empty AndAlso oConnectionId > -1 Then
|
|
' *** NEU: Skip Spalten mit #TBCOL# (werden in ShowingEditor behandelt) ***
|
|
If oSqlStatement.Contains("{#TBCOL#") Then
|
|
Logger.Debug($"GridTables_HandleControlValueChange -> Skipping column [{oColumnName}] (has #TBCOL# placeholders, will be resolved per row)")
|
|
Continue For
|
|
End If
|
|
|
|
' *** BESTEHENDER CODE: Nur für statische Spalten ({#CTRL#} only) ***
|
|
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
|