[DevExpress Support Team: CLONED FROM AS12152: Grid List Editors - How do I show both master and detail records in the same grid control (aka master-detail)]
I used second solution " Implement standard solutions for the GridControl …". Showing detail works fine, but as far as I use F5 to refresh data, details are not hidden/collapse together with master grid. Any recommendation to hide and dispose them?
Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.
Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.
Hello Libor,
Would you please attach a debuggable sample project showing your actual implementation so that we can find the most appropriate solution for you? You will likely need to continue using native grid solutions for expanding and collapsing detail records; e.g., DevExpress.XtraGrid.Views.Grid > GridView > CollapseMasterRow (if you are using WinForms).
Hi Dennis,
Everything happens in ViewController with this code (StockItemReservations is XPCollection):
using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using DevExpress.Data.Filtering; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Actions; using DevExpress.ExpressApp.Editors; using DevExpress.ExpressApp.Layout; using DevExpress.ExpressApp.Model.NodeGenerators; using DevExpress.ExpressApp.SystemModule; using DevExpress.ExpressApp.Templates; using DevExpress.ExpressApp.Utils; using DevExpress.Persistent.Base; using DevExpress.Persistent.Validation; using DevExpress.XtraGrid; using DevExpress.XtraGrid.Columns; using DevExpress.XtraGrid.Views.Grid; using DevExpress.XtraGrid.Views.Grid.ViewInfo; using ELVAC.HRP.Model.Enterprise.StockManagement; using ELVAC.EDF; namespace ELVAC.Huisman.HRP.Module.Win.Controllers { // For more typical usage scenarios, be sure to check out https://documentation.devexpress.com/eXpressAppFramework/clsDevExpressExpressAppViewControllertopic.aspx. public partial class StockItemViewController : ViewController { public StockItemViewController() { InitializeComponent(); // Target required Views (via the TargetXXX properties) and create their Actions. } protected override void OnActivated() { base.OnActivated(); // Perform various tasks depending on the target View. if (View is ListView) { View.ControlsCreated += new EventHandler(View_ControlsCreated); } } protected override void OnViewControlsCreated() { base.OnViewControlsCreated(); // Access and customize the target View control. } protected override void OnDeactivated() { if (View != null && View is ListView) { View.ControlsCreated -= new EventHandler(View_ControlsCreated); } if (View != null && View.IsControlCreated && View.Control != null && View.Control is GridControl) { GridControl grid = (GridControl)View.Control; if (grid.FocusedView is GridView) { GridView view = (GridView)grid.FocusedView; view.MasterRowGetRelationCount -= view_MasterRowGetRelationCount; view.MasterRowExpanded -= new CustomMasterRowEventHandler(view_MasterRowExpanded); view.MasterRowGetChildList -= view_MasterRowGetChildList; view.MasterRowEmpty -= view_MasterRowEmpty; view.CustomDrawCell -= view_CustomDrawCell; } } // Unsubscribe from previously subscribed events and release other references and resources. base.OnDeactivated(); } void View_ControlsCreated(object sender, EventArgs e) { if (View.Control is GridControl) { GridControl grid = (GridControl)View.Control; if (grid.FocusedView is GridView) { GridView view = (GridView)grid.FocusedView; view.OptionsDetail.ShowDetailTabs = false; view.OptionsView.ShowDetailButtons = true; view.OptionsDetail.EnableMasterViewMode = true; view.MasterRowGetRelationCount += view_MasterRowGetRelationCount; view.MasterRowExpanded += view_MasterRowExpanded; view.MasterRowCollapsed += view_MasterRowCollapsed; view.MasterRowGetChildList += view_MasterRowGetChildList; view.MasterRowEmpty += view_MasterRowEmpty; view.CustomDrawCell += view_CustomDrawCell; } } } void view_MasterRowCollapsed(object sender, CustomMasterRowEventArgs e) { GridView masterView = sender as GridView; if (masterView != null) { GridView detailView = masterView.GetDetailView(e.RowHandle, e.RelationIndex) as GridView; if (detailView != null) { detailView.BeginUpdate(); detailView.Dispose(); detailView.EndUpdate(); } } } void view_MasterRowEmpty(object sender, MasterRowEmptyEventArgs e) { GridView masterView = sender as GridView; if (masterView != null) { StockItem stockItem = masterView.GetRow(e.RowHandle) as StockItem; if (stockItem != null) { e.IsEmpty = stockItem == null || stockItem.StockItemReservations.Count <= 0; } } } void view_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e) { GridView view = sender as GridView; if (view != null) { if (e.Column.VisibleIndex == 0 && view.OptionsDetail.SmartDetailExpandButtonMode != DetailExpandButtonMode.AlwaysEnabled) { bool isMasterRowEmpty; if (view.OptionsDetail.SmartDetailExpandButtonMode == DetailExpandButtonMode.CheckAllDetails) { isMasterRowEmpty = true; for (int i = 0; i < view.GetRelationCount(e.RowHandle); i++) { if (!view.IsMasterRowEmptyEx(e.RowHandle, i)) { isMasterRowEmpty = false; break; } } } else { isMasterRowEmpty = view.IsMasterRowEmpty(e.RowHandle); } if (isMasterRowEmpty) { (e.Cell as GridCellInfo).CellButtonRect = Rectangle.Empty; } } } } void view_MasterRowGetChildList(object sender, MasterRowGetChildListEventArgs e) { GridView masterView = sender as GridView; if (e.RelationIndex == 0) { StockItem stockItem = masterView.GetRow(e.RowHandle) as StockItem; if (stockItem != null) { e.ChildList = stockItem.StockItemReservations;//select the required collection to show it in the detail view } } } void view_MasterRowGetRelationCount(object sender, MasterRowGetRelationCountEventArgs e) { e.RelationCount = 1;//to show only one detail view } void view_MasterRowExpanded(object sender, CustomMasterRowEventArgs e) { GridView masterView = sender as GridView; if (masterView != null) { GridView detailView = masterView.GetDetailView(e.RowHandle, e.RelationIndex) as GridView; if (detailView != null) { detailView.BeginUpdate(); detailView.OptionsDetail.EnableMasterViewMode = false; detailView.OptionsBehavior.Editable = false; detailView.OptionsView.ShowAutoFilterRow = false; detailView.OptionsView.ShowFooter = false; detailView.PopupMenuShowing += detailView_PopupMenuShowing; // hide columns... foreach (GridColumn column in detailView.Columns) { column.Visible = column.FieldName.Equals("ReservedFor") || column.FieldName.Equals("Quantity") || column.FieldName.Equals("Note") || column.FieldName.Equals("DateReserved") || column.FieldName.Equals("Note"); if (column.FieldName.Equals("Note")) { column.VisibleIndex = 4; } } detailView.BestFitColumns(true); detailView.EndUpdate(); } } } void detailView_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e) { e.Allow = false; } } }
Hi Libor,
I suggest that you check if you can remove the following code:
void view_MasterRowCollapsed(object sender, CustomMasterRowEventArgs e) { GridView masterView = sender as GridView; if (masterView != null) { GridView detailView = masterView.GetDetailView(e.RowHandle, e.RelationIndex) as GridView; if (detailView != null) { detailView.BeginUpdate(); detailView.Dispose(); detailView.EndUpdate(); } } }
If I have not missed anything important, you do not need to dispose of the GridView manually in this scenario. Try to remove this code to see if the issue is related to it.
If the manual disposal is required, please describe why. Perhaps, there is a safer way to address the corresponding issue.
Hi Uriah, view_MasterRowCollapsed method is gone, but issue is still there. Manual disposal is not needed.
Hi,
Please clarify what data source you are using for the grid and if you are working in Server Mode. I have created a small WinForms project based on your code. On my side, everything operates as expected. Would it be possible to modify my project or provide yours to illustrate the issue?
I look forward to your response.
Hi Svetlana, it's XAF application with XPO DataLayer. DataAccess is set to ServerMode - can be issue related to DataAccess mode?
Your sample working fine for me too.
According this page:
https://documentation.devexpress.com/WindowsForms/783/Controls-and-Libraries/Data-Grid/Master-Detail/Master-Detail-Overview
master-detail is not supported in ServerMode, right?
In fact, you can load detail data in a grid in Server Mode and in most cases it will operate properly. However, we did not adapt master-detail mode according to Server Mode specifics. Thus, there is no guarantee that the behavior will be correct in all the circumstances. That is why it is likely that the issue is caused by this fact. In any case, to determine this for sure, would you please extract the issue to a small XAF project and send it to us?
Here is a XAF project. Hope you will find any solution to hide details on refresh, because I can't disable ServerMode for this listview…
Hi,
I have reproduced the behavior and will discuss it with our developers. Once we have news for you, I will update this thread.
In the meantime, you can avoid this shortcoming by handling the RefreshController.RefreshAction.Executing event and calling the GridView.CollapseAllDetails method in the event handler:
public partial class StockItemViewController : ViewController { RefreshController controller; public StockItemViewController() { InitializeComponent(); // Target required Views (via the TargetXXX properties) and create their Actions. } protected override void OnActivated() { base.OnActivated(); // Perform various tasks depending on the target View. //... controller = Frame.GetController<RefreshController>(); if (controller != null) { controller.RefreshAction.Executing += RefreshAction_Executing; } } private void RefreshAction_Executing(object sender, System.ComponentModel.CancelEventArgs e) { GridControl grid = (GridControl)View.Control; if (grid.FocusedView is GridView) { GridView view = (GridView)grid.FocusedView; view.CollapseAllDetails(); } } protected override void OnDeactivated() { if (controller != null) { controller.RefreshAction.Executing -= RefreshAction_Executing; } //... // Unsubscribe from previously subscribed events and release other references and resources. base.OnDeactivated(); }
Hi Svetlana, any news from developers? RefreshController hook is not working.
Hi Libor,
Our developers are still researching the behavior. Once we have news for you, we will update this thread.
As for the suggested solution, it operates as expected on my side as shown in the attached video and project. Would you please test this project on your side?
Hi Libor,
Thank you for your patience. Our research shows that this issue seems to be fixed in the latest version, but it will be difficult to fix it in version 16.2. Please let us know if it is possible for you to upgrade to the latest build. If you want to test it first, feel free to download it using the following link: http://downloads.devexpress.com/Share/DXP/v17.1. Please let us know your result.
Hi Uriah,
Yes, upgrade is possible solution in this case. I will do it this week and let you know the result.
Thanks for your effort
Hi Uriah, it's working fine in v17.1.
Libor
Hi Libor,
Thank you for the confirmation!