482 lines
24 KiB
VB.net

Imports DevExpress.Utils
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Repository
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraGrid.Views.Grid
Imports DigitalData.Controls.LookupGrid
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.DatabaseWithFallback
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Base
Imports System.ComponentModel
Imports DevExpress.XtraEditors.Controls
Imports DevExpress.XtraGrid.Views.Base
Imports System.Text.RegularExpressions
Imports System.Globalization
Imports DevExpress.Xpo.Helpers.AssociatedCollectionCriteriaHelper
Imports DevExpress.XtraEditors.Mask
Namespace ControlCreator
Public Class GridControl
Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _Logger As Logger
Private ReadOnly _GridTables As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem))
Private newRowModified As Boolean
Public Sub New(pLogConfig As LogConfig, pGridTables As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem)))
_LogConfig = pLogConfig
_Logger = pLogConfig.GetLogger()
_GridTables = pGridTables
End Sub
Public Function CreateGridColumns(pColumnTable As DataTable) As DataTable
Dim oDataTable As New DataTable
For Each oRow As DataRow In pColumnTable.Rows
' Create Columns in Datatable
Dim oColumn = New DataColumn() With {
.ColumnName = oRow.Item("SPALTENNAME"),
.Caption = oRow.Item("SPALTEN_HEADER_LANG"),
.ReadOnly = False
}
Select Case oRow.Item("TYPE_COLUMN")
Case Constants.CONTROL_TYPE_TEXT
oColumn.DataType = GetType(String)
Case Constants.CONTROL_TYPE_INTEGER
oColumn.DataType = GetType(Integer)
Case Constants.CONTROL_TYPE_DOUBLE
oColumn.DataType = GetType(Double)
Case Constants.CONTROL_TYPE_CURRENCY
oColumn.DataType = GetType(Double)
Case Constants.CONTROL_TYPE_BOOLEAN
oColumn.DataType = GetType(Boolean)
Case Else
oColumn.DataType = GetType(String)
End Select
oDataTable.Columns.Add(oColumn)
Next
Return oDataTable
End Function
Public Function FillGridTables(pColumnTable As DataTable, pControlId As Integer, pControlName As String) As Dictionary(Of Integer, Dictionary(Of String, RepositoryItem))
For Each oRow As DataRow In pColumnTable.Rows
' Fetch and cache Combobox results
Dim oConnectionId As Integer = oRow.ItemEx("CONNECTION_ID", 0)
Dim oSqlCommand As String = oRow.ItemEx("SQL_COMMAND", "")
If oConnectionId > 0 And oSqlCommand <> "" Then
Try
Dim oComboboxDataTable As DataTable = Nothing
Dim oColumnName As String = oRow.Item("SPALTENNAME")
_Logger.Debug("Working on SQL for Column[{0}]...", oColumnName)
If Not clsPatterns.HasComplexPatterns(oSqlCommand) Then
_Logger.Debug("SQL has no complex patterns!")
'oComboboxDataTable = ClassDatabase.Return_Datatable_ConId(oSqlCommand, oConnectionId)
oComboboxDataTable = DatabaseFallback.GetDatatable(New GetDatatableOptions(oSqlCommand, DatabaseType.ECM) With {
.ConnectionId = oConnectionId
})
Else
_Logger.Debug("...has complex patterns!!")
End If
Dim oRepositoryItem = GridTables_GetRepositoryItemForColumn(oColumnName, oComboboxDataTable, oRow.Item("ADVANCED_LOOKUP"))
If _GridTables.Item(pControlId).ContainsKey(oColumnName) Then
_GridTables.Item(pControlId).Item(oColumnName) = oRepositoryItem
Else
_GridTables.Item(pControlId).Add(oColumnName, oRepositoryItem)
End If
Catch ex As Exception
_Logger.Warn("Could not load data for column {0} in control {1}", oRow.Item("SPALTENNAME"), pControlName)
_Logger.Error(ex)
End Try
End If
Next
Return _GridTables
End Function
Private 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 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
Dim oColumnData As DataRow = pColumnTable.
Select($"SPALTENNAME = '{oCol.FieldName}'").
FirstOrDefault()
If oColumnData Is Nothing Then
Continue For
End If
Dim oSequence As Integer = oColumnData.Item("SEQUENCE")
oCol.VisibleIndex = oSequence
Dim oColumnType As String = oColumnData.Item("TYPE_COLUMN")
Select Case oColumnType
Case "INTEGER"
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = "N0"
Case "DOUBLE"
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = "N2"
Case "CURRENCY"
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.DisplayFormat.FormatString = "C2"
End Select
Dim oSummaryFunction As String = oColumnData.Item("SUMMARY_FUNCTION")
Select Case oSummaryFunction
Case Constants.AGGREGATE_TOTAL_INTEGER
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N0}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_FLOAT
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:N2}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_CURRENCY
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
oCol.SummaryItem.DisplayFormat = "SUM: {0:C2}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_AVG
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Average
oCol.SummaryItem.DisplayFormat = "AVG: {0}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_MAX
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Max
oCol.SummaryItem.DisplayFormat = "MAX: {0}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_MIN
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Min
oCol.SummaryItem.DisplayFormat = "MIN: {0}"
oShouldDisplayFooter = True
Case Constants.AGGREGATE_TOTAL_COUNT
oCol.SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Count
oCol.SummaryItem.DisplayFormat = "NUM: {0}"
oShouldDisplayFooter = True
End Select
Next
pGridView.OptionsView.ShowFooter = oShouldDisplayFooter
End Sub
Public Sub ConfigureViewColumnsCurrency(pColumnTable As DataTable, pGridView As GridView, pGrid As DevExpress.XtraGrid.GridControl, pCurrency As String)
Dim oCultureInfo As CultureInfo = New CultureInfo("de-DE")
oCultureInfo.NumberFormat.CurrencySymbol = pCurrency
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 'Optional
pGrid.RepositoryItems.Add(riTextEdit)
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
End If
Dim oColumnType As String = oColumnData.Item("TYPE_COLUMN")
Select Case oColumnType
Case "CURRENCY"
oCol.DisplayFormat.FormatType = FormatType.Custom
oCol.ColumnEdit = riTextEdit
End Select
Next
End Sub
Public Sub ConfigureViewEvents(pColumnTable As DataTable, pGridView As GridView, pControl As Windows.Forms.Control, pControlId As Integer)
AddHandler pGridView.InitNewRow, Sub(sender As Object, e As InitNewRowEventArgs)
Try
_Logger.Debug("Initialzing new row")
For Each oColumnData As DataRow In pColumnTable.Rows
For Each oGridColumn As GridColumn In pGridView.Columns
If oGridColumn.FieldName <> oColumnData.Item("SPALTENNAME") Then
Continue For
End If
Dim oDefaultValue = ObjectEx.NotNull(oColumnData.Item("DEFAULT_VALUE"), String.Empty)
If oDefaultValue <> String.Empty Then
_Logger.Debug("Setting default value [{0}] for column [{1}]", oDefaultValue, oGridColumn.FieldName)
pGridView.SetRowCellValue(e.RowHandle, oGridColumn.FieldName, oDefaultValue)
End If
Next
Next
Catch ex As Exception
_Logger.Error(ex)
Finally
newRowModified = False
End Try
End Sub
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 oEditorExists = GridTables_TestEditorExistsByControlAndColumn(pControlId, oColumnName)
If oColumnName <> e.Column.FieldName Then
Continue For
End If
If oEditorExists Then
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)
End If
Next
Catch ex As Exception
_Logger.Warn("Error in CustomRowCellEdit for [{0}]", e.CellValue)
_Logger.Error(ex)
End Try
End Sub
AddHandler pGridView.ValidatingEditor, Sub(sender As Object, e As BaseContainerValidateEditorEventArgs)
Dim oRow As DataRowView = pGridView.GetRow(pGridView.FocusedRowHandle)
Dim oColumnName = pGridView.FocusedColumn.FieldName
_Logger.Debug("Validating Editor for Column [{0}]", oColumnName)
GridTables_ValidateColumn(pGridView, pColumnTable, oColumnName, e.Value, e.Valid, e.ErrorText)
End Sub
AddHandler pGridView.PopupMenuShowing, AddressOf View_PopupMenuShowing
AddHandler pGridView.InvalidRowException, AddressOf View_InvalidRowException
AddHandler pGridView.ValidatingEditor, AddressOf View_ValidatingEditor
' AddHandler pGridView.CustomColumnDisplayText, AddressOf View_CustomColumnDisplayText
' These handlers are all used for the custom DefaultValue functionality, additionally some code in the 'InitNewRow' event.
' https://supportcenter.devexpress.com/ticket/details/t1035580/how-to-default-a-value-in-a-column-when-add-new-row-in-data-grid
AddHandler pGridView.ShowingEditor, AddressOf View_ShowingEditor
AddHandler pGridView.ShownEditor, AddressOf View_ShownEditor
AddHandler pGridView.ValidateRow, AddressOf View_ValidateRow
AddHandler pControl.LostFocus, AddressOf Control_LostFocus
End Sub
Private Sub View_CustomColumnDisplayText(ByVal eSender As Object, ByVal e As CustomColumnDisplayTextEventArgs)
If IsNothing(e.Value) Then
Exit Sub
End If
Dim view As GridView = eSender
'Dim view As GridView = TryCast(GridView1, GridView)
If e.Column.FieldName = "SpalteCurrency" Then
' e.DisplayText = e.Value.ToString().Replace("€", "CHF")
End If
End Sub
Private Sub View_PopupMenuShowing(sender As Object, e As PopupMenuShowingEventArgs)
Dim view As GridView = TryCast(sender, GridView)
Dim oFocusedColumn As GridColumn = view.FocusedColumn
Dim oColumnType As Type = oFocusedColumn.ColumnType
Dim oColumnName As String = oFocusedColumn.FieldName
If e.MenuType = GridMenuType.Column AndAlso oColumnType Is GetType(Boolean) Then
e.Menu.Items.Add(New Menu.DXMenuItem(
"Alle Zeilen anhaken",
Sub(_sender As Object, _e As EventArgs)
SetCellValuesForBooleanColumn(view, oColumnName, True)
End Sub,
My.Resources.itemtypechecked,
Menu.DXMenuItemPriority.Normal))
e.Menu.Items.Add(New Menu.DXMenuItem(
"Alle Zeilen abhaken",
Sub(_sender As Object, _e As EventArgs)
SetCellValuesForBooleanColumn(view, oColumnName, False)
End Sub,
My.Resources.itemtypechecked,
Menu.DXMenuItemPriority.Normal))
End If
End Sub
Private Sub SetCellValuesForBooleanColumn(pView As GridView, pColumnName As String, pValue As Boolean)
Dim oRowHandle = 0
While (pView.IsValidRowHandle(oRowHandle))
Dim oRow = pView.GetDataRow(oRowHandle)
Dim oValue = oRow.ItemEx(pColumnName, False)
oRow.Item(pColumnName) = pValue
oRowHandle += 1
End While
End Sub
Private Sub Control_LostFocus(sender As DevExpress.XtraGrid.GridControl, e As EventArgs)
Dim oView2 As GridView = sender.FocusedView
' 19.08.2022:
' Calling UpdateCurrentRow when newRowModified Is true
' leads to some weird jumping of focus in the current cell.
' This seems to fix it.
If newRowModified = False Then
oView2.UpdateCurrentRow()
End If
End Sub
Private Sub View_ShowingEditor(sender As Object, e As CancelEventArgs)
Dim view As GridView = TryCast(sender, GridView)
_Logger.Debug("Showing editor.")
If view.IsNewItemRow(view.FocusedRowHandle) AndAlso Not newRowModified Then
_Logger.Debug("Adding new row.")
view.AddNewRow()
End If
End Sub
Private Sub View_ShownEditor(sender As Object, e As EventArgs)
Dim view As GridView = TryCast(sender, GridView)
If view.IsNewItemRow(view.FocusedRowHandle) Then
_Logger.Debug("Attaching Modified Handler.")
AddHandler view.ActiveEditor.Modified, Sub()
_Logger.Debug("Row was modified.")
newRowModified = True
End Sub
End If
End Sub
Private Sub View_ValidateRow(sender As Object, e As ValidateRowEventArgs)
Dim view As GridView = TryCast(sender, GridView)
If view.IsNewItemRow(e.RowHandle) AndAlso Not newRowModified Then
_Logger.Debug("Deleting unused row")
view.DeleteRow(e.RowHandle)
End If
_Logger.Debug("Validating row. Resetting Modified.")
newRowModified = False
End Sub
Private Sub View_ValidatingEditor(sender As Object, e As BaseContainerValidateEditorEventArgs)
Dim oValue As String = ObjectEx.NotNull(e.Value, "")
If oValue.Contains(" | ") Then
oValue = oValue.Split(" | ").ToList().First()
e.Value = oValue
End If
End Sub
Private Sub View_InvalidRowException(sender As Object, e As InvalidRowExceptionEventArgs)
e.ExceptionMode = ExceptionMode.NoAction
End Sub
Private Function GridTables_TestEditorExistsByControlAndColumn(oControlId As Integer, pColumn As String) As Boolean
If _GridTables.ContainsKey(oControlId) Then
Dim oContainsKey = _GridTables.Item(oControlId).ContainsKey(pColumn)
If oContainsKey AndAlso _GridTables.Item(oControlId).Item(pColumn) IsNot Nothing Then
Return True
Else
Return False
End If
Else
Return False
End If
End Function
Private Function GridTables_ValidateColumn(pView As GridView, pColumnDefinition As DataTable, ColumnName As String, pValue As Object, ByRef pIsValid As Boolean, ByRef pErrorText As String) As Boolean
Dim oColumn As DataRow = (From r As DataRow In pColumnDefinition.Rows
Where r.Item("SPALTENNAME") = ColumnName
Select r).FirstOrDefault()
Dim oGridColumn As GridColumn = (From c As GridColumn In pView.Columns
Where c.FieldName = ColumnName
Select c).FirstOrDefault()
Dim oIsRequired = oColumn.Item("VALIDATION")
Try
Dim oRegex = ObjectEx.NotNull(oColumn.Item("REGEX_MATCH"), String.Empty)
Dim oRegexMessage = ObjectEx.NotNull(oColumn.Item("REGEX_MESSAGE_DE"), String.Empty)
If oRegex <> String.Empty Then
Dim oMatch = New Regex(oRegex).IsMatch(pValue.ToString)
Dim oDefaultMessage = "Wert entspricht nicht dem gefordertem Format!"
Dim oMessage = IIf(oRegexMessage <> String.Empty, oRegexMessage, oDefaultMessage)
If oMatch = False Then
pErrorText = oMessage
pIsValid = False
Return False
End If
End If
Catch ex As Exception
_Logger.Error(ex)
End Try
If oIsRequired And (pValue IsNot Nothing AndAlso pValue.ToString = "") Then
pErrorText = "Spalte muss ausgefüllt werden!"
pIsValid = False
Return False
End If
Return True
End Function
End Class
End Namespace