diff --git a/app/DD-Record-Organizer/OrgFlow.vbproj b/app/DD-Record-Organizer/OrgFlow.vbproj index f27543c..ab10c5c 100644 --- a/app/DD-Record-Organizer/OrgFlow.vbproj +++ b/app/DD-Record-Organizer/OrgFlow.vbproj @@ -193,9 +193,9 @@ False - + False - ..\..\..\..\2_DLL Projekte\DDMonorepo\Controls.DocumentViewer\bin\Debug\DigitalData.Controls.DocumentViewer.dll + ..\..\..\..\2_DLL Projekte\Controls.DocumentViewer\bin\Debug\DigitalData.Controls.DocumentViewer.dll ..\..\..\..\2_DLL Projekte\DDMonorepo\GUIs.Common\bin\Debug\DigitalData.GUIs.Common.dll diff --git a/app/DD-Record-Organizer/frmDocSearchResult.vb b/app/DD-Record-Organizer/frmDocSearchResult.vb index 5d49bb8..c783ccc 100644 --- a/app/DD-Record-Organizer/frmDocSearchResult.vb +++ b/app/DD-Record-Organizer/frmDocSearchResult.vb @@ -99,7 +99,7 @@ Public Class frmDocSearchResult Refresh_DocID() If SplitContainerControl1.Collapsed = False Then Dim OFilePath = ClassHelper.FORMAT_WM_PATH(SelectedFULL_FILEPATH) - DocumentViewer1.LoadFile(OFilePath) + DocumentViewer1.LoadFile_FromPath(OFilePath) End If End Sub Sub Refresh_DocID() diff --git a/app/DD-Record-Organizer/frmNodeNavigation.vb b/app/DD-Record-Organizer/frmNodeNavigation.vb index 1b30e2b..95886a7 100644 --- a/app/DD-Record-Organizer/frmNodeNavigation.vb +++ b/app/DD-Record-Organizer/frmNodeNavigation.vb @@ -145,13 +145,14 @@ Public Class frmNodeNavigation End If checkShowPreview.Checked = CONFIG.Config.DocumentViewerShown + UpdateDocViewCollapsedState() Catch ex As Exception NNLogger.Error(ex) ClassHelper.MSGBOX_Handler("ERROR", "Unexpected Error", ex.Message, ex.StackTrace) End Try End Sub - Private Async Function frmNodeNavigation_Load(sender As Object, e As EventArgs) As Task Handles Me.Load + Private Async Sub frmNodeNavigation_Load(sender As Object, e As EventArgs) Handles Me.Load NNLogger.Debug("Loading NodeNavigation") CONSTRUCTORID = CURRENT_CONSTRUCTOR_ID @@ -228,7 +229,7 @@ Public Class frmNodeNavigation LOGGER?.Info("FilesDroppedReady: " & String.Join("; ", files)) ' ... bestehende Routine aufrufen ... End Sub - End Function + End Sub Private Async Function Load_nodes() As Task Dim oHandle = SplashScreenManager.ShowOverlayForm(Me) NNLogger.Debug("Loading nodes for entity [{0}]", CURRENT_ENTITY_ID) @@ -239,32 +240,47 @@ Public Class frmNodeNavigation Dim oNodeConfigSql = String.Format("select T.* from TBPMO_STRUCTURE_NODES_CONFIGURATION T INNER JOIN VWPMO_CONSTRUCTOR_FORMS T1 ON T.ENTITY_ID = T1.FORM_ID WHERE T.ENTITY_ID = {0}", CURRENT_ENTITY_ID) Dim DT_TREEVIEW_CONFIGURATION = MYDB_ECM.GetDatatable(oNodeConfigSql) - For Each row As DataRow In DT_TREEVIEW_CONFIGURATION.Rows - Try - Dim bimage = row.ItemEx(Of Object)("NODE_IMAGE", Nothing) - If bimage Is Nothing Then - Continue For - End If - Dim oNodeImage = ByteArrayToBitmap(bimage) - ImageCollection1.AddImage(oNodeImage, row.Item("GUID")) - Catch ex As Exception - NNLogger.Error(ex) - End Try - Next + Dim imageInit = TryCast(ImageCollection1, System.ComponentModel.ISupportInitialize) + If imageInit IsNot Nothing Then + imageInit.BeginInit() + End If - TreeListDevexpress.DataSource = DT_STRUCTURE_NODES - TreeListDevexpress.KeyFieldName = "GUID" - TreeListDevexpress.ParentFieldName = "PARENT_GUID" - TreeListDevexpress.Columns("SEQUENCE").SortOrder = SortOrder.Ascending - TreeListDevexpress.StateImageList = ImageCollection1 + Try + For Each row As DataRow In DT_TREEVIEW_CONFIGURATION.Rows + Try + Dim bimage = row.ItemEx(Of Object)("NODE_IMAGE", Nothing) + If bimage Is Nothing Then + Continue For + End If - Dim oVisibleColumns = New List(Of String) From {"NODE_CAPTION"} ', "NAVIGATION_PATH"} - For Each oColumn In TreeListDevexpress.Columns - If oVisibleColumns.Contains(oColumn.FieldName) = False Then - oColumn.Visible = False + Dim oNodeImage = ByteArrayToBitmap(bimage) + ImageCollection1.AddImage(oNodeImage, row.Item("GUID")) + Catch ex As Exception + NNLogger.Error(ex) + End Try + Next + Finally + If imageInit IsNot Nothing Then + imageInit.EndInit() End If - Next + End Try + + TreeListDevexpress.BeginUpdate() + Try + TreeListDevexpress.DataSource = DT_STRUCTURE_NODES + TreeListDevexpress.KeyFieldName = "GUID" + TreeListDevexpress.ParentFieldName = "PARENT_GUID" + TreeListDevexpress.Columns("SEQUENCE").SortOrder = SortOrder.Ascending + TreeListDevexpress.StateImageList = ImageCollection1 + + Dim oVisibleColumns As New System.Collections.Generic.HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {"NODE_CAPTION"} + For Each oColumn As TreeListColumn In TreeListDevexpress.Columns + oColumn.Visible = oVisibleColumns.Contains(oColumn.FieldName) + Next + Finally + TreeListDevexpress.EndUpdate() + End Try JumptoNode() @@ -325,10 +341,6 @@ Public Class frmNodeNavigation Exit Sub End If MyFocusedNode = Nothing - If btnCreateNewNode.Visibility = DevExpress.XtraBars.BarItemVisibility.Always Then - btnCreateNewNode.Enabled = False - End If - If RIGHT_RECORD_AND_FILE_READ_ONLY = True Then Exit Sub @@ -392,23 +404,23 @@ Public Class frmNodeNavigation CurrentNodeConfigId = oNodeConfigId AvailableConfigNodes.Clear() - If btnCreateNewNode.Visibility = DevExpress.XtraBars.BarItemVisibility.Always And - Not IsNothing(NODE_CONFIGURABLE_NODES_DT) Then + If Not IsNothing(NODE_CONFIGURABLE_NODES_DT) Then Dim oNodeConfigList = NODE_CONFIGURABLE_NODES_DT.Select($"PARENT_NODE = {oNodeConfigId}"). - Cast(Of DataRow). - Select(Function(row) New frmNewNode.NodeConfig() With { - .Id = row.Item("GUID"), - .Name = row.Item("NAME") - }).ToList() + Cast(Of DataRow). + Select(Function(row) New frmNewNode.NodeConfig() With { + .Id = row.Item("GUID"), + .Name = row.Item("NAME") + }).ToList() AvailableConfigNodes = oNodeConfigList - - If AvailableConfigNodes.Count > 0 Then - btnCreateNewNode.Enabled = True - Else - btnCreateNewNode.Enabled = False - End If End If + NNLogger.Info($"Node changed: NodeID={oNodeConfigId}, NodeGUID={oGuid}, ConfigNodesFound={AvailableConfigNodes.Count}, " & + $"ButtonVisible={btnCreateNewNode.Visibility}, ConfigTableRows={If(IsNothing(NODE_CONFIGURABLE_NODES_DT), 0, NODE_CONFIGURABLE_NODES_DT.Rows.Count)}") + + + ' NEUE zentrale Methode aufrufen statt direkter Manipulation + UpdateCreateNodeButtonState() + ' END NEW NODE CURRENT_NODEID = oGuid @@ -431,7 +443,7 @@ Public Class frmNodeNavigation Await Show_Selected_Record_Data(CURRENT_RECORD_ID, oLoadRecordData) - DocView_DisplaySelectedDoc(True) + Await DocView_DisplaySelectedDoc(True) ClassRightManagement.Check_Set_Rights(CURRENT_RECORD_ID, _EntityId) CONTROL_HANDLING() @@ -492,6 +504,48 @@ Public Class frmNodeNavigation End If End If End Sub + ' Neue zentrale Methode zum konsistenten Setzen des Button-Status + Private Sub UpdateCreateNodeButtonState() + Try + ' *** HIER: Eingangsdiagnose *** + NNLogger.Debug($"UpdateCreateNodeButtonState called - Visibility={btnCreateNewNode.Visibility}, " & + $"CurrentEnabled={btnCreateNewNode.Enabled}, AvailableNodes={AvailableConfigNodes.Count}, " & + $"ConfigTableExists={Not IsNothing(NODE_CONFIGURABLE_NODES_DT)}") + + If btnCreateNewNode.Visibility <> DevExpress.XtraBars.BarItemVisibility.Always Then + Exit Sub + End If + + ' Button aktivieren wenn: + ' 1. Konfigurierbare Nodes existieren UND + ' 2. Verfügbare Config-Nodes für aktuellen Node vorhanden sind + Dim shouldEnable As Boolean = False + + If Not IsNothing(NODE_CONFIGURABLE_NODES_DT) AndAlso + NODE_CONFIGURABLE_NODES_DT.Rows.Count > 0 AndAlso + AvailableConfigNodes.Count > 0 Then + shouldEnable = True + End If + + ' Thread-sicheres Update + If Me.InvokeRequired Then + Me.Invoke(Sub() btnCreateNewNode.Enabled = shouldEnable) + Else + btnCreateNewNode.Enabled = shouldEnable + End If + + If shouldEnable Then + LOGGER.Debug($"btnCreateNewNode ENABLED (AvailableConfigNodes: {AvailableConfigNodes.Count})") + Else + LOGGER.Debug($"btnCreateNewNode DISABLED (ConfigNodes: {AvailableConfigNodes.Count})") + End If + + Catch ex As Exception + NNLogger.Error(ex) + ' Im Fehlerfall: Sicherheitshalber deaktivieren + btnCreateNewNode.Enabled = False + End Try + End Sub Public Async Function ShowDialogAsync() As Task(Of DialogResult) Return Await Task.Run(Function() Return MessageBox.Show("Der Parent-Node wird nun getauscht? Wollen Sie fortfahren?", @@ -657,9 +711,15 @@ Public Class frmNodeNavigation btnCreateNewNode.Visibility = DevExpress.XtraBars.BarItemVisibility.Never Dim oSql = String.Format("SELECT * FROM TBPMO_STRUCTURE_NODES_CONFIGURATION where TYPE_NODE = 1000 AND ENTITY_ID IN (SELECT FORM_ID FROM VWPMO_CONSTRUCTOR_FORMS WHERE CONSTRUCT_ID = {0})", oConstructID) NODE_CONFIGURABLE_NODES_DT = MYDB_ECM.GetDatatable(oSql) + + NNLogger.Info($"Load_Configurable_Nodes: ConstructID={oConstructID}, " & + $"FoundRows={If(IsNothing(NODE_CONFIGURABLE_NODES_DT), 0, NODE_CONFIGURABLE_NODES_DT.Rows.Count)}") + If Not IsNothing(NODE_CONFIGURABLE_NODES_DT) Then If NODE_CONFIGURABLE_NODES_DT.Rows.Count > 0 Then btnCreateNewNode.Visibility = DevExpress.XtraBars.BarItemVisibility.Always + ' Initial-State setzen + UpdateCreateNodeButtonState() End If End If Catch ex As Exception @@ -984,7 +1044,7 @@ Public Class frmNodeNavigation Else RibbonPageGroupDocResult.Enabled = True If Node_AfterSelect = False Then - SplitContainerDocView.Collapsed = Not CONFIG.Config.DocumentViewerShown + UpdateDocViewCollapsedState() Else SplitContainerDocView.Collapsed = True End If @@ -1837,9 +1897,9 @@ Public Class frmNodeNavigation End Try sw.Done() End Sub - Private Sub OnCBSelectedValueChanged(sender As Object, e As EventArgs) + Private Async Sub OnCBSelectedValueChanged(sender As Object, e As EventArgs) Try - Dim oDocID = Focused_Row_GetDocID() + Dim oDocID = Await Focused_Row_GetDocID() ' ✅ Mit Await If oDocID = 0 Then Exit Sub End If @@ -1875,9 +1935,9 @@ Public Class frmNodeNavigation End Try End Sub - Private Sub OnDateSelectedValueChanged(sender As Object, e As EventArgs) + Private Async Sub OnDateSelectedValueChanged(sender As Object, e As EventArgs) Try - Dim oDocID = Focused_Row_GetDocID() + Dim oDocID = Await Focused_Row_GetDocID() ' ✅ Mit Await If oDocID = 0 Then Exit Sub End If @@ -1923,9 +1983,9 @@ Public Class frmNodeNavigation End Try End Sub - Private Sub OnTextSelectedValueChanged(sender As Object, e As EventArgs) + Private Async Sub OnTextSelectedValueChanged(sender As Object, e As EventArgs) Try - Dim oDocID = Focused_Row_GetDocID() + Dim oDocID = Await Focused_Row_GetDocID() ' ✅ Mit Await If oDocID = 0 Then Exit Sub End If @@ -1956,10 +2016,10 @@ Public Class frmNodeNavigation End Try End Sub - Private Sub OnCheckboxValueChanged(sender As Object, e As EventArgs) + Private Async Sub OnCheckboxValueChanged(sender As Object, e As EventArgs) 'TODO Save Checkboxvalue Try - Dim oDocID = Focused_Row_GetDocID() + Dim oDocID = Await Focused_Row_GetDocID() ' ✅ Mit Await If oDocID = 0 Then Exit Sub End If @@ -2003,32 +2063,42 @@ Public Class frmNodeNavigation End Try End Sub - Private Sub GridViewDoc_Search_FocusedRowChanged(sender As Object, e As DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs) Handles GridViewDoc_Search.FocusedRowChanged - Focused_Row_GetDocID() - + Private Async Sub GridViewDoc_Search_FocusedRowChanged(sender As Object, e As DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs) Handles GridViewDoc_Search.FocusedRowChanged + ' ✅ Jetzt mit Await aufrufen + Dim docId = Await Focused_Row_GetDocID() End Sub - Private Function Focused_Row_GetDocID() As Int64 + Private Async Function Focused_Row_GetDocID() As Task(Of Int64) Try + ' Early Exit 1: Formular noch nicht angezeigt If FORM_SHOWN = False Then Return 0 End If + + ' Early Exit 2: Node-Wechsel aktiv If Node_AfterSelect = True Then SplitContainerDocView.Collapsed = True GridViewDoc_Search.ClearSelection() GridViewDoc_Search.FocusedRowHandle = DevExpress.XtraGrid.GridControl.InvalidRowHandle - Return 0 End If + Update_DocID_Label(False) Update_Notification_Label(False, "", "") + + ' Prüfung: Ist eine Zeile fokussiert? If GridViewDoc_Search.FocusedRowHandle >= 0 Then Dim oDocID = GridViewDoc_Search.GetRowCellValue(GridViewDoc_Search.FocusedRowHandle, "DocID") + If Not IsNothing(oDocID) Then Dim omsg = "Doc-ID: " & oDocID Update_DocID_Label(True, omsg, EditState.Update) + + ' ✅ Dokumentvorschau nur bei DocID-Wechsel aktualisieren If SELECTED_DOC_ID <> oDocID Then SELECTED_DOC_ID = oDocID + + ' Panel-Status setzen (falls Vorschau deaktiviert) If checkShowPreview.Checked = False Then SplitContainerDocView.Collapsed = True Else @@ -2037,8 +2107,10 @@ Public Class frmNodeNavigation End If End If - DocView_DisplaySelectedDoc(False) + ' ✅ Async-Aufruf mit Await + Await DocView_DisplaySelectedDoc(False) End If + Update_DocID_Label(True, omsg, EditState.Update) Return SELECTED_DOC_ID Else @@ -2049,6 +2121,7 @@ Public Class frmNodeNavigation Return 0 End If Catch ex As Exception + NNLogger.Error(ex, "Error in Focused_Row_GetDocID") Return 0 End Try End Function @@ -3228,18 +3301,28 @@ Public Class frmNodeNavigation Private Sub bbtnitmRecSave_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtnitmRecSave.ItemClick Save_Record() End Sub - - Private Sub checkShowPreview_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles checkShowPreview.CheckedChanged + ''' + ''' Setzt den Collapsed-Status des DocumentViewer-Panels konsistent. + ''' Panel ist nur aufgeklappt, wenn DocViewInitialized = True UND checkShowPreview.Checked = True + ''' + Private Sub UpdateDocViewCollapsedState() + If DocViewInitialized AndAlso checkShowPreview.Checked Then + SplitContainerDocView.Collapsed = False + Else + SplitContainerDocView.Collapsed = True + End If + End Sub + Private Async Sub checkShowPreview_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles checkShowPreview.CheckedChanged If FORM_LOADED = False Then Exit Sub End If If DocViewInitialized Then CONFIG.Config.DocumentViewerShown = checkShowPreview.Checked CONFIG.Save() - SplitContainerDocView.Collapsed = Not checkShowPreview.Checked - If checkShowPreview.Checked Then - DocView_DisplaySelectedDoc(False) - End If + ' ✅ Konsistente zentrale Methode verwenden + UpdateDocViewCollapsedState() + + Await DocView_DisplaySelectedDoc(False) Else SplitContainerDocView.Collapsed = True @@ -3247,104 +3330,48 @@ Public Class frmNodeNavigation End Sub - Private Sub GridViewDoc_Search_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridViewDoc_Search.SelectionChanged - DocView_DisplaySelectedDoc(False) + Private Async Sub GridViewDoc_Search_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridViewDoc_Search.SelectionChanged + Await DocView_DisplaySelectedDoc(False) End Sub - Private Async Sub DocView_DisplaySelectedDoc(AfterNodeChange As Boolean) + Private Async Function DocView_DisplaySelectedDoc(AfterNodeChange As Boolean) As Task + ' ✅ Early Exit: Keine Vorschau nach Node-Wechsel If AfterNodeChange Then - Exit Sub + Return + End If + + ' ✅ Early Exit: Vorschau ist deaktiviert + If Not checkShowPreview.Checked Then + NNLogger.Info("checkShowPreview NOT Checked.") + Return + End If + ' ✅ Early Exit: Viewer nicht initialisiert + If Not DocViewInitialized Then + NNLogger.Info("DocumentViewer not initialized. No preview possible.") + Return End If Dim oHandle = SplashScreenManager.ShowOverlayForm(Me) Try Dim oSelectedDoc = ClassDocGrid.GetSingleSelectedDocument(GridViewDoc_Search) - If Not IsNothing(oSelectedDoc) Then - If checkShowPreview.Checked Then - If DocViewInitialized Then - If oSelectedDoc.Count = 1 Then - Close_Document_Viewer() - System.Threading.Thread.Sleep(400) - Dim oDocument As ClassDocGrid.clsWMDoc = oSelectedDoc.First() - Dim oPath = ClassHelper.FORMAT_WM_PATH(oDocument.DocPath) - DocumentViewer.LoadFile(oPath) - Else - NNLogger.Debug("Show_SelectedDoc - oSelectedDocs.Count not = 1 ") - Close_Document_Viewer() - End If - Else - NNLogger.Info("DocumentViewer not inited. No Show_SelectedDoc") - End If - End If - - Else - NNLogger.Debug("Show_SelectedDoc - oSelectedDocs is nothing") + If IsNothing(oSelectedDoc) OrElse oSelectedDoc.Count <> 1 Then + NNLogger.Debug("No single document selected for preview. Check oSelectedDoc count: " & If(IsNothing(oSelectedDoc), "oSelectedDoc is Nothing", oSelectedDoc.Count.ToString())) + Close_Document_Viewer() + Return End If + ' ✅ Alle Prüfungen bestanden → Dokument laden + Close_Document_Viewer() + Await Task.Delay(400) + Dim oDocument As ClassDocGrid.clsWMDoc = oSelectedDoc.First() + Dim oPath = ClassHelper.FORMAT_WM_PATH(oDocument.DocPath) - - - - - - ' If AfterNodeChange Then Exit Sub - - 'Dim oHandle = SplashScreenManager.ShowOverlayForm(Me) - - 'Try - ' Dim oSelectedDoc = ClassDocGrid.GetSingleSelectedDocument(GridViewDoc_Search) - - ' If oSelectedDoc Is Nothing OrElse oSelectedDoc.Count <> 1 Then - ' NNLogger.Debug("Kein oder mehrere Dokumente ausgewählt.") - ' Close_Document_Viewer() - ' Return - ' End If - - ' If Not checkShowPreview.Checked OrElse Not DocViewInitialized Then - ' NNLogger.Info("Vorschau deaktiviert oder Viewer nicht initialisiert.") - ' Return - ' End If - - ' Close_Document_Viewer() - ' Await Task.Delay(400) - - ' Dim oDocument As ClassDocGrid.clsWMDoc = oSelectedDoc.First() - ' Dim oPath = ClassHelper.FORMAT_WM_PATH(oDocument.DocPath) - ' NNLogger.Debug("Starte DocumentViewer.LoadFile...") - - ' ' Flag für Erfolg - ' Dim fileLoadedSuccessfully As Boolean = False - - ' ' Starte Timeout-Überwachung - ' Dim timeoutTask = Task.Delay(TimeSpan.FromSeconds(20)) - - ' ' Starte Laden im UI-Thread - ' Dim loadTask = Task.Run(Sub() - ' Try - ' ' Direkt im UI-Thread ausführen - ' Me.Invoke(Sub() - ' DocumentViewer.LoadFile(oPath) - ' fileLoadedSuccessfully = True - ' End Sub) - ' Catch ex As Exception - ' NNLogger.Error("Fehler beim Laden des Dokuments: " & ex.Message) - ' End Try - ' End Sub) - - ' ' Warte auf Timeout oder Ladeende - ' Await Task.WhenAny(loadTask, timeoutTask) - - ' If Not fileLoadedSuccessfully Then - ' NNLogger.Warn("Ladevorgang hat Timeout überschritten oder ist fehlgeschlagen.") - ' ' Optional: Viewer zurücksetzen oder Meldung anzeigen - ' Else - ' NNLogger.Info("Dokument erfolgreich geladen.") - ' End If + DocumentViewer.LoadFile_FromPath(oPath) Catch ex As Exception NNLogger.Error(ex) Finally SplashScreenManager.CloseOverlayForm(oHandle) End Try - End Sub + End Function