Goal
Our application needs to allow end users to dynamically customize the Telerik Blazor DockManager at runtime by:
These changes should be fully user-driven and persisted so that:
In short, we want the DockManager to behave as a customizable dashboard whose state can be reliably stored and reloaded from our database.
Problem
The current Telerik Blazor DockManager implementation requires panels to be declared in Razor markup (markup driven) and managed through an external data source.
This creates several challenges:
As a result, implementing a truly dynamic and persistent DockManager layout requires complex workarounds that are fragile and difficult to maintain.
Feature Request
We propose enhancing the DockManager with first-class support for dynamic panel synchronization by introducing:
Two coordinated parameters:
Expected behavior:
This would allow developers to treat the DockManager as a true data-driven component, similar to other Telerik Blazor controls, without needing to manually modify internal state structures.
Hello Gary,
Thank you for this clarification. Removing an already declared pane in the DockManager is not currently a supported scenario, but it seems to me like a valid use case.
To completely remove a pane, you must remove it from the declaration (e.g., if you iterate over a collection of objects to declare panes, remove the object from that collection) and then re-render the component. Alternatively, you must exclude it from the state and ensure it is no longer declared.
===
Regarding your questions:
State Structure Changes: It is highly unlikely we will change the state structure, as the preserve state functionality and most of the internal logic of the component relies on it. Any modification would be a major breaking change.
API Enhancements: Since manual state manipulation is difficult, we are considering exposing API methods to exclude panes from the structure.
Data-Driven DockManager: This is not a direct solution to this specific problem, as exposing the root pane(which is what we can basically expose) would still require tree traversal to remove a specific node.
Exposing a configuration or method to remove panes from the current state is a valid feature request. If this meets your requirements, we can log it separately and close this thread.
===
As for whether your current implementation might break in the future: it is unlikely. While I cannot guarantee 0% change, the core logic relies on this structure. We generally state that manual state manipulations are unsupported because an invalid structure (e.g., a tab pane containing a child split pane) will cause exceptions. If your modifications follow the valid DockManager structural rules, the component should function correctly.
Regarding your second question: "Does the safe container approach eliminate the need to traverse the DockManagerState...?"
Essentially, yes. However, if your current implementation is already working as intended, switching approaches may not be necessary.
Please let me know if you need additional information or if you would like to log a feature request for methods to exclude panes after declaration.
Regards,
Yanislav
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Thank you for the detailed explanation regarding the Closeable behavior and the safe container approach.
Remove / Close Pane
We understand this is a shared implementation, and it sounds like the behavior is intended to mimic the show/hide model used in applications such as the Call Stack window in Microsoft Visual Studio, where there is one instance that is shown or hidden and never removed.
In our case, however, we allow a pane/tile of a given type to be added more than once (multiple instances), and we want a pane to be fully removed when the user chooses, since it will never be restored. During our call, it was mentioned that there should be no need to manipulate the DockManagerState, but this scenario appears to be one where direct state modification becomes necessary.
Currently, in order to fully remove panes from the layout, we are manipulating the DockManagerState directly to remove the corresponding pane entries. This approach works functionally, but it requires traversing and modifying the DockManagerState structure, which we consider fragile because it depends on internal implementation details that may change in future releases.
Could you please clarify the following:
• Is directly modifying DockManagerState to remove panes considered a supported and stable pattern, or is it viewed as an internal workaround that may be impacted by future updates?
• Is there a recommended or officially supported mechanism to fully remove panes from the layout state when panes are dynamically created?
• Should applications treat DockManagerState as an implementation detail that may change across versions, or can its structure be relied upon for programmatic manipulation?
Our goal is to be resilient to future Telerik updates while still supporting dynamic pane lifecycle management (frequent add/remove operations) without allowing the state to grow indefinitely with hidden panes.
Introducing an optional parameter such as DeleteOnClose (or similar) could provide a clear and explicit mechanism for scenarios where a pane should be permanently removed rather than hidden. This seems like it could be a useful feature request for applications that support multiple dynamic pane instances.
Adding Panes to Safe Container
We understand the intent of the "safe container" approach as providing a stable location for dynamically added panes, and that model appears compatible with our design. However, our primary concern remains the long-term reliability of relying on DockManagerState traversal and manipulation.
You mentioned the following approach:
"You can compare the initial state (captured when OnStateInit is triggered) with the current state obtained via the GetState method whenever a new pane is added. You can also track layout changes by monitoring the OnStateChanged event."
Does the safe container approach eliminate the need to traverse the DockManagerState, or would state traversal still be required in order to support dynamic pane addition?
We already have a solution to adding panes, and it appears that both solutions require traversing the DockManagerState. Is switching to "safe containers" worth the effort?
Recall, our objective is to ensure our application remains resilient to future Telerik updates.
Yanislav,
That worked beautifully! For my purposes I'm good to go! I'll defer back to the original requester but thank you for looking at this!
Hello Craig,
You can add new panes inside both floating and non-floating containers, however, to support dynamic insertion, the parent container must persist.
Please review this example: https://blazorrepl.telerik.com/GguRnbYK55cx0zD648.
It uses a DockManagerSplitPane with AllowEmpty="true", which acts as the necessary anchor for adding content panes dynamically. While this differs slightly from inserting panes directly as children of DockManagerPanes, it ensures the structure remains intact. Let me know if this approach meets your requirements.
Regards,
Yanislav
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Hello again Yanislav,
Thank you for your help. I am happy to make another issue but I think fundamentally it is the same issue.
Requirement: When new ContentPanes are first added AFTER the first render of TelerikDockManager, render them so they are available.
What is happening now: If a ContentPane is added AFTER the first render (either somewhere in the <DockManagerPanes> or the <DockManagerFloatingPanes> hierarchy), Telerik creates a "dummy placeholder" for the ContentPane.
Why is this happening?: Because the only time content panes are rendered now is on the first call to TelerikDockManager.OnAfterRenderAsync
Why is this a problem: Scenarios where the content is chosen by the user (a very common scenario) is difficult
What is the current workaround: Either (1) Flash the screen to drop and re-render the entire DockManager - very bad (2) Create a bunch of hidden ContentPanes in a floating container, then manage their use - works but not ideal.
The problem is clear - we need to be able to add content panes after the first render of TelerikDockManager.
All of the existing commentary has just been offering possible solutions to that issue, solve it however you like but please solve it. Thank you!
Craig
Hello Gary,
I will try to answer your questions below:
1. As for the Closeable parameter - by design, a closed pane is not a removed pane. While adding a built-in UI for restoring closed panes is a valid feature request, they currently remain in the state because restoring them (setting Visible="true") forces the DockManager to find their appropriate place in the layout based on their last visible position.
The state becomes "bloated" because the shared implementation continuously adds new pane instances instead of restoring closed ones. You can bind the Visible field (@bind-Visible="paneEntity.Visible") and toggle the value after a pane is closed to restore it. This ensures it renders in the correct location without adding new panes. You can define all panes initially as non-visible and "restore" them to render. This is supported and works dynamically. REPL Example: https://blazorrepl.telerik.com/mKYHQyOs58W2gWNk12
Alternatively, if you require dynamically added panes with unknown content, you can use the safe container approach discussed earlier.
In short to your questions:
> Using Closeable, is there a way to identify closed panes?
Since you are defining panes from a dataset, you can bind the panes and identify closed panes by filtering for those where `Visible == false`.
> Using Closeable, is there a way to remove a pane from the DockStateManager rather than setting Visible to false?
Currently, the Close button implementation simply raises the `VisibleChanged` event with a value of `false`.
> Is there a way to determine whether the layout stored in DockManagerState differs from the layout defined in the Razor page?
You can compare the initial state (captured when OnStateInit is triggered) with the current state obtained via the GetState method whenever a new pane is added. You can also track layout changes by monitoring the OnStateChanged event.
> If the layout differs from the Razor layout, can we conditionally use a "safe container"; otherwise, use the default layout?
Yes, this is a viable solution. You must ensure that the container where new panes are added remains present and is not destroyed by the DockManager.
I hope this information helps. Let me know if you need further assistance.
===
Hello Craig,
Thank you for your feedback and your interest in enhancing the DockManager component.
Could you please elaborate on the specific use case? I want to ensure I fully understand the purpose of the DynamicContentPanes configuration and its expected behavior. Since the DockManager utilizes a parent-child structure rather than flat collections that can be concatenated, it is currently unclear how these dynamic panes would render or interact with the existing hierarchy.
I am also interested in the requirement for dynamic parameters and how you envision them functioning. To provide the best possible solution, it would be helpful to understand your ultimate end goal rather than the specific configuration needs.
Side note: This appears to differ from the initial requirement in this thread. If so, to keep our communication organized, could you please open a separate thread to describe your goal and exact requirements?
Thank you for the additional details in advance.
Regards,
Yanislav
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
I am adding my comments as someone who would also like a solution to the problem of dynamically adding ContentPanes.
The *only* solution that I could get to work at the moment was to add blank hidden panes to my own hidden floating splitter panel, then manage their placement on my own. It works fine but I have to create as many as I -think- I would need which can be inefficient. I would rather a solution like this:
POSSIBLE SOLUTION 1 - Add DynamicContentPanes parameter
- Include a DynamicContentPanes list parameter within the component. The TelerikDockManagerDynamicContentPane would look something like this:
When rendering, see if any changes have occurred to DynamicContentPanes, and then perform the initial render of any new content panes.
Ideally it would also dispose of any dynamic content panes no longer present and follow the existing logic to update the DockState (e.g., leave a hole if AllowEmpty, etc. - no new logic just use what you already have)
If a DynamicContentPane is not specified in the layout, just keep it hidden within the special floating pane used to house DynamicContentPane items.
Add a OnDynamicContentChanged event - similar to OnStateInit where we can then situate the new content where we want by getting/setting the supplied DockState event argument.
This would be a non-breaking change. For me I would switch solely to DynamicContentPanes since that is my use case.
POSSIBLE SOLUTION 2 - Render any new DockManagerContentPane when first introduced
- On .Refresh or state change, rescan the defined <DockManagerPanes> and <DockManagerFloatingPanes> looking for new DockManagerContentPanes (or derived class). If present, perform its initial render and add it to the tracking context.
At present, OnAfterRenderAsync is only ever rendering any content on the first render. This is where the problem occurs.
I would prefer Solution 1, but either solution would work.
This would be an extremely useful addition to an already excellent component!
Hi Yanislav,
Resize Evenly
Correct, there is only one implementation for Resize Evenly, and it is used in the demo for both the Default and Workaround modes. The default behavior of our tiles/panes is to resize evenly using a configurable number of columns. If a user changes the number of columns or selects Resize Evenly, then their current layout is lost and they are presented with all of their tiles/panes evenly spaced. You may have noticed this feature works correctly only in Workaround mode. In Default mode, the problem begins with the Closeable feature
When Closeable is set to true, panes can be closed using the DockManagerContentPane's close button:
<DockManagerContentPane Class="" Unpinnable="false" Closeable="true" AllowFloat="true" Id="@ccy.Key" VisibleChanged="OnVisibleChanged">
Closing a pane sets the pane's Visible property false and fires the OnVisibleChange . This results in two problems:
If the closed pane cannot be identified, then it cannot be removed from the data source. The technique used with @key is to reset the layout (or resize evenly) exposes this issue because previously closed panes reappear.
In Workaround mode, Closeable is set to false and a custom button is added in the header template to remove the tile/pane. Using a custom remove button allows the application to:
Questions:
Adding Panes
The suggestion to add a "safe container" may work; however, we need a way to determine whether the layout has changed. The layout defined in the Razor page is the desired layout initially, or when the user selects Resize Evenly. Adding Panes works well until the user modifies the layout.
Our requirement is:
Questions
Hi Gary,
Thank you for preparing the example and the video, I was able to reproduce the behavior.
I will try to address the issues separately:
The DockManager definition and its state are not synced. Once a user changes the layout, the definition and the state of the panes differ.
In your project, a split pane is rendered for each column. These are defined with AllowEmpty="false". This tells the DockManager to destroy any pane/splitter/column that has no children. By design, all parent panes (tab groups and splitter panes) are destroyed when empty.
You can keep these panes by setting AllowEmpty="true". This ensures the pane remains so new records can be rendered inside it. Otherwise, once a parent pane is left without children, the DockManager ignores it. This is the reason why sometimes the panes are not included even though they are part of the dataset.
If your goal is to avoid empty panes while keeping the AllowEmpty="false" configuration, you have two options:
This allows you to keep the column structure so new content panes are inserted evenly. Here is an example demonstrating this approach: https://blazorrepl.telerik.com/GAaHvWvI20ym4GK113
Handling this manually requires tracking onDock and onUndock to count children for each column. I see an opportunity to improve this by exposing an event that tracks when a parent pane is left without children. This would allow you to hide and show it automatically. Let me know if you are interested in this feature, and we can log it for implementation.
A data-driven approach will not simplify the process of adding new panes because the DockManager utilizes a multiple-tree structure. In this architecture, floating panes act as independent "mini-dockmanager" trees managed by the component.
Even if root panes are exposed, adding dynamic panes still requires you to access the current state and traverse the structure to identify the correct parent node.
If your primary goal is to add new panes into the layout, a more efficient method is to define an empty splitter pane and iterate your data within it. This acts as a "safe container" for dynamic children.
Please let me know if you would like me to prepare an example of this configuration.
===
Please correct me if I am mistaken, but the resize button in the provided example appears to function identically in both the workaround and default modes.
public async Task ResizeEvenly()
{
await InvokeAsync(async () =>
{
Console.WriteLine("Resize Evenly");
DockManagerKey = Guid.NewGuid().ToString();
this.StateHasChanged();
});
TelerikNotificationRef?.Show(new NotificationModel() { Icon = Telerik.SvgIcons.SvgIcon.Check, CloseAfter = NotificationTimeout, ThemeColor = ThemeConstants.Notification.ThemeColor.Success, Text = $"Resized Evenly with {Columns} Columns." });
}I am not entirely sure of the exact purpose of this method, as it changes the @key directive value of the DockManager component. By default, if no Size parameter is passed to a pane, the splitter children are sized evenly. Changing the @key value triggers a complete re-render of the component, which resets all panes to their initial defined positions and calculates their size.
Sizing all content panes evenly can currently be achieved without re-rendering the entire component. However, this requires traversing the state, calculating the sibling count for each content pane, and manually setting its Size parameter. Since such implementation is complex, exposing a dedicated method to resize all panes evenly can be logged as a separate feature request.
However, I would like to ask you to elaborate more on your ultimate goal for this so we can discuss the best approach.
Please review these suggestions and let me know if I have missed any specific requirements.
Regards,
Yanislav
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Hello Gary,
Thank you for attaching a solution and a video. We are in the process of reviewing and validating the requirements and will get back to you shortly.
Regards,
Ivan Danchev
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
100%!
Running into this issue now - quite tricky, every solution feels brittle.
Hello Gary,
Thank you for the comprehensive explanation of the problem you are facing with the current DockManager capabilities and the functionality you've requested.
I've made the feature request public on our Feedback Portal, which would allow other members of the community to vote for it.
Regards,
Ivan Danchev
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.