From 51912b36c272ef1633285dc9303234383b1ca624 Mon Sep 17 00:00:00 2001 From: Jonathan Jenne Date: Fri, 8 Apr 2022 13:17:46 +0200 Subject: [PATCH] Add virtual property to field value, improve ui when loading files, improve initial loading --- MultiTool.Common/Constants.vb | 8 ++ MultiTool.Common/Documents/DocumentLoader.vb | 61 +++++++++++--- MultiTool.Common/Documents/DocumentRow.vb | 86 +++++++++++++++++--- MultiTool.Form/frmImportMain.vb | 7 ++ MultiTool.Form/frmMain.Designer.vb | 60 +++++++------- MultiTool.Form/frmMain.vb | 33 ++++++-- MultiTool.Form/frmRowEditor.vb | 9 +- 7 files changed, 201 insertions(+), 63 deletions(-) diff --git a/MultiTool.Common/Constants.vb b/MultiTool.Common/Constants.vb index 125b6b7..44065a8 100644 --- a/MultiTool.Common/Constants.vb +++ b/MultiTool.Common/Constants.vb @@ -55,6 +55,14 @@ [Boolean] [Decimal] End Enum + + Public Enum FieldError + None + MissingValue + AccountNotFound + ArticleNotFound + End Enum + Public Enum XmlFunction None = 0 GLN = 1 diff --git a/MultiTool.Common/Documents/DocumentLoader.vb b/MultiTool.Common/Documents/DocumentLoader.vb index 6687534..f1fb948 100644 --- a/MultiTool.Common/Documents/DocumentLoader.vb +++ b/MultiTool.Common/Documents/DocumentLoader.vb @@ -6,6 +6,7 @@ Imports MultiTool.Common.Exceptions Imports MultiTool.Common.Templates Imports MultiTool.Common.Winline Imports MultiTool.Common.Winline.Entities +Imports MultiTool.Common.Constants Namespace Documents Public Class DocumentLoader @@ -16,12 +17,32 @@ Namespace Documents Private ReadOnly TemplateConfig As TemplateConfig Public Property Files As New List(Of Document) + + Public Property FilesTotal As Integer = 0 + Public Property FilesLoaded As Integer = 0 + Public Event FileLoadComplete As EventHandler(Of FileLoadInfo) + Public Event FileLoadProgress As EventHandler(Of FileLoadProgressInfo) - Public Structure FileLoadInfo + Public Class FileLoadInfo Public FilesLoaded As Integer Public FilesTotal As Integer - End Structure + + Public Sub New(pTotal As Integer, pLoaded As Integer) + FilesTotal = pTotal + FilesLoaded = pLoaded + End Sub + End Class + + Public Class FileLoadProgressInfo + Inherits FileLoadInfo + + Public RunningFunction As String + + Public Sub New(pTotal As Integer, pLoaded As Integer) + MyBase.New(pTotal, pLoaded) + End Sub + End Class Public Sub New(pLogConfig As LogConfig, pWinline As WinlineData, pMappingConfig As MappingConfig, pTemplateConfig As TemplateConfig) MyBase.New(pLogConfig) @@ -37,6 +58,7 @@ Namespace Documents Try Dim oDirectory As New DirectoryInfo(pTemplate.InputDirectory) Dim oFiles = oDirectory.GetFiles() + FilesTotal = oFiles.Count Logger.Debug("Found [{0}] files in directory [{1}]", oFiles.Count, oDirectory) @@ -44,11 +66,9 @@ Namespace Documents Try Dim oDocument = Await LoadFile(oFile, pTemplate, pMandator) Files.Add(oDocument) + FilesLoaded = Files.Count - Dim oInfo As FileLoadInfo - oInfo.FilesLoaded = Files.Count - oInfo.FilesTotal = oFiles.Count - + Dim oInfo As New FileLoadInfo(FilesTotal, FilesLoaded) RaiseEvent FileLoadComplete(Me, oInfo) Catch ex As MissingAttributeException @@ -179,17 +199,19 @@ Namespace Documents .Final = oValue, .DataType = oColumn.DataType, .IsRequired = oRequired, + .IsVirtual = oColumn.Config.IsVirtual, .SortKey = oColumnSortKey }) Else - Dim oColumnError = DocumentRow.FieldError.None + Dim oColumnError = FieldError.None If oColumn.Config?.IsRequired Then - oColumnError = DocumentRow.FieldError.MissingValue + oColumnError = FieldError.MissingValue End If oFields.Add(oColumn.Name, New DocumentRow.FieldValue With { .[Error] = oColumnError, - .SortKey = oColumnSortKey + .SortKey = oColumnSortKey, + .IsVirtual = oColumn.Config.IsVirtual }) End If @@ -224,6 +246,9 @@ Namespace Documents OrderBy(Function(m) m.Order). ToList() + Dim oInfo As New FileLoadProgressInfo(FilesTotal, FilesLoaded) With {.RunningFunction = "Mandant finden"} + RaiseEvent FileLoadProgress(Me, oInfo) + Dim oMandator As Mandator = Nothing If pMandator IsNot Nothing Then oMandator = pMandator @@ -237,12 +262,24 @@ Namespace Documents ' Set mandator befor applying any functions that depend on a valid mandator pDocument.Mandator = oMandator + RaiseEvent FileLoadProgress(Me, New FileLoadProgressInfo(FilesTotal, FilesLoaded) With { + .RunningFunction = "Winline-Funktionen" + }) + pDocument = ApplyDefinedItemFunctionsForImport(pDocument, oMandator, pTemplate) pDocument = ApplyDynamicItemFunctionsForImport(pDocument, oMandator) + RaiseEvent FileLoadProgress(Me, New FileLoadProgressInfo(FilesTotal, FilesLoaded) With { + .RunningFunction = "Preis-Funktionen" + }) + ' These functions will only be applied if the document does not have errors pDocument = Await MaybeApplyPriceFunctions(pDocument, oMandator, pTemplate) + RaiseEvent FileLoadProgress(Me, New FileLoadProgressInfo(FilesTotal, FilesLoaded) With { + .RunningFunction = "Feld-Funktionen" + }) + ' This function needs to be the last one because ' it can relate to any previously set value ApplyFieldFunctionForImport(pDocument, oMandator, pTemplate) @@ -449,7 +486,7 @@ Namespace Documents Dim oDocumentKindField As String = oFieldMap.GetOrDefault("DocumentKind", Nothing) Dim oDocumentKind As Integer = 0 - If Integer.TryParse(pDocument.GetFieldValue(oDocumentKindField), oDocumentKind) Then + If Integer.TryParse(pDocument.GetFieldValue(oDocumentKindField), oDocumentKind) = False Then Logger.Warn("Value for parameter DocumentKind could not be parsed. Setting to 0.") End If @@ -479,7 +516,7 @@ Namespace Documents oNumberItem.External = oArticleNumber oNumberItem.Final = oArticleNumber Else - oNumberItem.Error = DocumentRow.FieldError.ArticleNotFound + oNumberItem.Error = FieldError.ArticleNotFound End If End Sub @@ -513,7 +550,7 @@ Namespace Documents '}) End If Else - oNumberItem.Error = DocumentRow.FieldError.AccountNotFound + oNumberItem.Error = FieldError.AccountNotFound End If End Sub diff --git a/MultiTool.Common/Documents/DocumentRow.vb b/MultiTool.Common/Documents/DocumentRow.vb index 999a99d..3c2fb15 100644 --- a/MultiTool.Common/Documents/DocumentRow.vb +++ b/MultiTool.Common/Documents/DocumentRow.vb @@ -1,4 +1,7 @@ -Namespace Documents +Imports System.Text.RegularExpressions +Imports MultiTool.Common.Constants + +Namespace Documents Public Class DocumentRow Implements IComparable @@ -48,19 +51,45 @@ Return SortKey.CompareTo(DirectCast(other, DocumentRow).SortKey) End Function - Public Enum FieldError - None - MissingValue - AccountNotFound - ArticleNotFound - End Enum - Public Class FieldValue + Private _Final As String = "" + Private _External As String = "" + Private _Original As String = "" + Public Property DataType As Constants.ColumnType = Constants.ColumnType.String Public Property [Error] As FieldError = FieldError.None - Public Property Original As String = "" - Public Property External As String = "" - Public Property Final As String = "" + + Public Sub New() + + End Sub + + Public Property Original As String + Get + Return FormatValue(_Original, DataType) + End Get + Set(value As String) + _Original = value + End Set + End Property + + Public Property External As String + Get + Return FormatValue(_External, DataType) + End Get + Set(value As String) + _External = value + End Set + End Property + + Public Property Final As String + Get + Return FormatValue(_Final, DataType) + End Get + Set(value As String) + _Final = value + End Set + End Property + Public Property IsRequired As Boolean = False Public Property IsVirtual As Boolean = False Public Property SortKey As Integer = 0 @@ -87,6 +116,41 @@ Public Overrides Function ToString() As String Return Final End Function + + Private Function FormatValue(pValue As String, pType As Constants.ColumnType) As String + Select Case pType + Case ColumnType.Decimal + Return FormatDecimalValue(pValue) + + Case Else + Return pValue + End Select + End Function + + ''' + ''' This function will capture values like below and format them according to winline format values + ''' + ''' 1000 + ''' 1.000.000 + ''' 1.000.000,00 + ''' + ''' A string value that represents a number + ''' A string value which contains at dot (.) as the decimal divider + Private Function FormatDecimalValue(pValue As String) As String + If Not pValue.Contains(","c) Then + Return pValue + End If + + Dim oRegex = New Regex("(?\d+(?:\.\d+)*(?:,\d+)?)") + Dim oMatch = oRegex.Match(pValue) + + If oMatch.Success Then + Dim oValue = oMatch.Groups.Item("Value").Value + Return oValue.Replace(","c, "."c) + Else + Return pValue + End If + End Function End Class End Class diff --git a/MultiTool.Form/frmImportMain.vb b/MultiTool.Form/frmImportMain.vb index 1ed1d5e..241fb27 100644 --- a/MultiTool.Form/frmImportMain.vb +++ b/MultiTool.Form/frmImportMain.vb @@ -615,6 +615,13 @@ Public Class frmImportMain SplashScreenManager.SetWaitFormDescription(oMessage) End Sub + AddHandler DocumentLoader.FileLoadProgress, Sub(_sender As Object, _e As Documents.DocumentLoader.FileLoadProgressInfo) + Dim oMessage = String.Format("Lade Dateien ({0}/{1}): {2}", _e.FilesLoaded, _e.FilesTotal, _e.RunningFunction) + SplashScreenManager.SetWaitFormDescription(oMessage) + End Sub + + SplashScreenManager.SetWaitFormDescription(String.Format("Lade Dateien ({0}/{1})", 0, DocumentLoader.Files.Count)) + If Await DocumentLoader.LoadFiles(CurrentTemplate, lookupMandator.EditValue) Then GridControlFiles.DataSource = Nothing GridControlFiles.DataSource = DocumentLoader.Files diff --git a/MultiTool.Form/frmMain.Designer.vb b/MultiTool.Form/frmMain.Designer.vb index 4e9016f..d6f81d8 100644 --- a/MultiTool.Form/frmMain.Designer.vb +++ b/MultiTool.Form/frmMain.Designer.vb @@ -32,15 +32,15 @@ Partial Class frmMain Me.btnOpenSchemaDirectory = New DevExpress.XtraBars.BarButtonItem() Me.btnReloadWinlineData = New DevExpress.XtraBars.BarButtonItem() Me.RibbonPage1 = New DevExpress.XtraBars.Ribbon.RibbonPage() - Me.RibbonPageGroup1 = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() - Me.RibbonPageGroup3 = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() + Me.RibbonPageGroupStart = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() + Me.RibbonPageGroupData = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() Me.RibbonPage3 = New DevExpress.XtraBars.Ribbon.RibbonPage() Me.RibbonPageGroup2 = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() Me.RibbonPageGroup4 = New DevExpress.XtraBars.Ribbon.RibbonPageGroup() Me.RibbonStatusBar1 = New DevExpress.XtraBars.Ribbon.RibbonStatusBar() Me.RibbonPage2 = New DevExpress.XtraBars.Ribbon.RibbonPage() Me.SvgImageCollection1 = New DevExpress.Utils.SvgImageCollection(Me.components) - Me.GridControl1 = New DevExpress.XtraGrid.GridControl() + Me.GridControlTemplates = New DevExpress.XtraGrid.GridControl() Me.GridViewTemplates = New DevExpress.XtraGrid.Views.Grid.GridView() Me.colName = New DevExpress.XtraGrid.Columns.GridColumn() Me.colDescription = New DevExpress.XtraGrid.Columns.GridColumn() @@ -48,7 +48,7 @@ Partial Class frmMain Me.SplashScreenManager = New DevExpress.XtraSplashScreen.SplashScreenManager(Me, GetType(Global.MultiTool.Form.frmWaitForm), True, True) CType(Me.RibbonControl1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.SvgImageCollection1, System.ComponentModel.ISupportInitialize).BeginInit() - CType(Me.GridControl1, System.ComponentModel.ISupportInitialize).BeginInit() + CType(Me.GridControlTemplates, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.GridViewTemplates, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' @@ -133,23 +133,23 @@ Partial Class frmMain ' 'RibbonPage1 ' - Me.RibbonPage1.Groups.AddRange(New DevExpress.XtraBars.Ribbon.RibbonPageGroup() {Me.RibbonPageGroup1, Me.RibbonPageGroup3}) + Me.RibbonPage1.Groups.AddRange(New DevExpress.XtraBars.Ribbon.RibbonPageGroup() {Me.RibbonPageGroupStart, Me.RibbonPageGroupData}) Me.RibbonPage1.Name = "RibbonPage1" Me.RibbonPage1.Text = "Start" ' - 'RibbonPageGroup1 + 'RibbonPageGroupStart ' - Me.RibbonPageGroup1.ItemLinks.Add(Me.btnOpenImportExportForm) - Me.RibbonPageGroup1.Name = "RibbonPageGroup1" - Me.RibbonPageGroup1.Text = "Start" + Me.RibbonPageGroupStart.ItemLinks.Add(Me.btnOpenImportExportForm) + Me.RibbonPageGroupStart.Name = "RibbonPageGroupStart" + Me.RibbonPageGroupStart.Text = "Start" ' - 'RibbonPageGroup3 + 'RibbonPageGroupData ' - Me.RibbonPageGroup3.Alignment = DevExpress.XtraBars.Ribbon.RibbonPageGroupAlignment.Far - Me.RibbonPageGroup3.ItemLinks.Add(Me.btnReloadTemplates) - Me.RibbonPageGroup3.ItemLinks.Add(Me.btnReloadWinlineData) - Me.RibbonPageGroup3.Name = "RibbonPageGroup3" - Me.RibbonPageGroup3.Text = "Daten" + Me.RibbonPageGroupData.Alignment = DevExpress.XtraBars.Ribbon.RibbonPageGroupAlignment.Far + Me.RibbonPageGroupData.ItemLinks.Add(Me.btnReloadTemplates) + Me.RibbonPageGroupData.ItemLinks.Add(Me.btnReloadWinlineData) + Me.RibbonPageGroupData.Name = "RibbonPageGroupData" + Me.RibbonPageGroupData.Text = "Daten" ' 'RibbonPage3 ' @@ -191,21 +191,21 @@ Partial Class frmMain Me.SvgImageCollection1.Add("import", "image://svgimages/scheduling/import.svg") Me.SvgImageCollection1.Add("export", "image://svgimages/export/export.svg") ' - 'GridControl1 + 'GridControlTemplates ' - Me.GridControl1.Dock = System.Windows.Forms.DockStyle.Fill - Me.GridControl1.Location = New System.Drawing.Point(0, 158) - Me.GridControl1.MainView = Me.GridViewTemplates - Me.GridControl1.MenuManager = Me.RibbonControl1 - Me.GridControl1.Name = "GridControl1" - Me.GridControl1.Size = New System.Drawing.Size(757, 355) - Me.GridControl1.TabIndex = 9 - Me.GridControl1.ViewCollection.AddRange(New DevExpress.XtraGrid.Views.Base.BaseView() {Me.GridViewTemplates}) + Me.GridControlTemplates.Dock = System.Windows.Forms.DockStyle.Fill + Me.GridControlTemplates.Location = New System.Drawing.Point(0, 158) + Me.GridControlTemplates.MainView = Me.GridViewTemplates + Me.GridControlTemplates.MenuManager = Me.RibbonControl1 + Me.GridControlTemplates.Name = "GridControlTemplates" + Me.GridControlTemplates.Size = New System.Drawing.Size(757, 355) + Me.GridControlTemplates.TabIndex = 9 + Me.GridControlTemplates.ViewCollection.AddRange(New DevExpress.XtraGrid.Views.Base.BaseView() {Me.GridViewTemplates}) ' 'GridViewTemplates ' Me.GridViewTemplates.Columns.AddRange(New DevExpress.XtraGrid.Columns.GridColumn() {Me.colName, Me.colDescription, Me.colFileName}) - Me.GridViewTemplates.GridControl = Me.GridControl1 + Me.GridViewTemplates.GridControl = Me.GridControlTemplates Me.GridViewTemplates.Name = "GridViewTemplates" ' 'colName @@ -241,7 +241,7 @@ Partial Class frmMain Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font Me.ClientSize = New System.Drawing.Size(757, 537) - Me.Controls.Add(Me.GridControl1) + Me.Controls.Add(Me.GridControlTemplates) Me.Controls.Add(Me.RibbonStatusBar1) Me.Controls.Add(Me.RibbonControl1) Me.IconOptions.SvgImage = Global.MultiTool.Form.My.Resources.Resources.squarified @@ -252,7 +252,7 @@ Partial Class frmMain Me.Text = "frmMain" CType(Me.RibbonControl1, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.SvgImageCollection1, System.ComponentModel.ISupportInitialize).EndInit() - CType(Me.GridControl1, System.ComponentModel.ISupportInitialize).EndInit() + CType(Me.GridControlTemplates, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.GridViewTemplates, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) Me.PerformLayout() @@ -260,12 +260,12 @@ Partial Class frmMain End Sub Friend WithEvents RibbonControl1 As DevExpress.XtraBars.Ribbon.RibbonControl Friend WithEvents RibbonPage1 As DevExpress.XtraBars.Ribbon.RibbonPage - Friend WithEvents RibbonPageGroup1 As DevExpress.XtraBars.Ribbon.RibbonPageGroup + Friend WithEvents RibbonPageGroupStart As DevExpress.XtraBars.Ribbon.RibbonPageGroup Friend WithEvents RibbonStatusBar1 As DevExpress.XtraBars.Ribbon.RibbonStatusBar Friend WithEvents RibbonPage2 As DevExpress.XtraBars.Ribbon.RibbonPage Friend WithEvents btnOpenImportExportForm As DevExpress.XtraBars.BarButtonItem Friend WithEvents SvgImageCollection1 As DevExpress.Utils.SvgImageCollection - Friend WithEvents GridControl1 As DevExpress.XtraGrid.GridControl + Friend WithEvents GridControlTemplates As DevExpress.XtraGrid.GridControl Friend WithEvents GridViewTemplates As DevExpress.XtraGrid.Views.Grid.GridView Friend WithEvents colName As DevExpress.XtraGrid.Columns.GridColumn Friend WithEvents colDescription As DevExpress.XtraGrid.Columns.GridColumn @@ -276,7 +276,7 @@ Partial Class frmMain Friend WithEvents BarButtonItem4 As DevExpress.XtraBars.BarButtonItem Friend WithEvents BarButtonItem2 As DevExpress.XtraBars.BarButtonItem Friend WithEvents BarButtonItem3 As DevExpress.XtraBars.BarButtonItem - Friend WithEvents RibbonPageGroup3 As DevExpress.XtraBars.Ribbon.RibbonPageGroup + Friend WithEvents RibbonPageGroupData As DevExpress.XtraBars.Ribbon.RibbonPageGroup Friend WithEvents SplashScreenManager As DevExpress.XtraSplashScreen.SplashScreenManager Friend WithEvents txtVersion As DevExpress.XtraBars.BarStaticItem Friend WithEvents txtCulture As DevExpress.XtraBars.BarStaticItem diff --git a/MultiTool.Form/frmMain.vb b/MultiTool.Form/frmMain.vb index 7a4e9c5..3c07838 100644 --- a/MultiTool.Form/frmMain.vb +++ b/MultiTool.Form/frmMain.vb @@ -27,15 +27,16 @@ Public Class frmMain Logger = LogConfig.GetLogger() Logger.Info("Starting {0}, Version [{1}]", Application.ProductName, Application.ProductVersion) + ShowLoadingUI() + Catch ex As Exception FormHelper.ShowError(ex, My.Resources.frmShared.Laden_des_Formulars) + HideLoadingUI() End Try End Sub Private Async Sub frmMain_Shown(sender As Object, e As EventArgs) Handles Me.Shown - SplashScreenManager.ShowWaitForm() - Try SplashScreenManager.SetWaitFormDescription("Initialisierung der Grundfunktionen") @@ -70,7 +71,7 @@ Public Class frmMain Database = New MSSQLServer(LogConfig, oConnectionString) SplashScreenManager.SetWaitFormDescription("Lade Vorlagen") - GridControl1.DataSource = Await LoadTemplateData() + GridControlTemplates.DataSource = Await LoadTemplateData() SplashScreenManager.SetWaitFormDescription("Lade Winline Stammdaten") My.Winline = New WinlineData(LogConfig, Database, My.GeneralConfiguration, My.MappingConfiguration, My.MandatorConfiguration) @@ -82,7 +83,7 @@ Public Class frmMain FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Laden_der_Winline_Daten) Finally - SplashScreenManager.CloseWaitForm() + HideLoadingUI() End Try End Sub @@ -238,17 +239,17 @@ Public Class frmMain Exit Sub End If - SplashScreenManager.ShowWaitForm() + ShowLoadingUI() Try SplashScreenManager.SetWaitFormDescription("Lade Vorlagen") - GridControl1.DataSource = Await LoadTemplateData() + GridControlTemplates.DataSource = Await LoadTemplateData() Catch ex As Exception FormHelper.ShowError(ex, "Laden der Vorlagen") Finally - SplashScreenManager.CloseWaitForm() + HideLoadingUI() End Try End Sub @@ -258,7 +259,7 @@ Public Class frmMain Exit Sub End If - SplashScreenManager.ShowWaitForm() + ShowLoadingUI() Try SplashScreenManager.SetWaitFormDescription("Lade Winline Stammdaten") @@ -268,8 +269,22 @@ Public Class frmMain FormHelper.ShowError(ex, My.Resources.frmImportMainExtra.Laden_der_Winline_Daten) Finally - SplashScreenManager.CloseWaitForm() + HideLoadingUI() End Try End Sub + + Private Sub ShowLoadingUI() + SplashScreenManager.ShowWaitForm() + GridControlTemplates.Enabled = False + RibbonPageGroupData.Enabled = False + RibbonPageGroupStart.Enabled = False + End Sub + + Private Sub HideLoadingUI() + GridControlTemplates.Enabled = True + RibbonPageGroupData.Enabled = True + RibbonPageGroupStart.Enabled = True + SplashScreenManager.CloseWaitForm() + End Sub End Class \ No newline at end of file diff --git a/MultiTool.Form/frmRowEditor.vb b/MultiTool.Form/frmRowEditor.vb index 6460e81..f670fb0 100644 --- a/MultiTool.Form/frmRowEditor.vb +++ b/MultiTool.Form/frmRowEditor.vb @@ -117,6 +117,8 @@ Public Class frmRowEditor End If If oField.Value Is Nothing Then + ' TODO: Do we need to create a new field value here? + ' aka. do we need to configure fieldvalue from column settings oDict.Add(oColumnName, New FieldValue()) Else oDict.Add(oColumnName, oField.Value) @@ -154,6 +156,10 @@ Public Class frmRowEditor Where(Function(f) f.Key = oRow.Item(COL_KEY)). SingleOrDefault() + ' TODO: Why do we need to create new fieldvalues here? + ' aka. why would the be a value for which no fieldvalue exists yet? + ' If there are (non-virtual) fields in the template which do not have a value yet, + ' this might happen. If oField.Key Is Nothing Then oField = New KeyValuePair(Of String, FieldValue)(oRow.Item(COL_KEY), New FieldValue()) End If @@ -173,10 +179,11 @@ Public Class frmRowEditor If Not oFieldValue.Final.Equals(oValueFromGrid) Then ' If new value is not empty, any error will be removed. ' Could cause problems in the future because a value might not equal to 'no error'. - ' 03.12.21: For now we always remove the error if ANYTHING changed about the field 'If oValueFromGrid <> String.Empty Then ' oFieldValue.Error = FieldError.None 'End If + + ' 03.12.21: For now we always remove the error if ANYTHING changed about the field oFieldValue.Error = FieldError.None ' Save the grid value to the Field