Overview
One of the key concepts when building an application stays the layout – what should it be? How should it be defined? It’s a tough question with lots of different answers. Of course, Telerik always tries to make the development easier and here is our answer as simple as possible – the combination of RadMenu and RadDocking controls.
Let’s assume we want to build an IDE or any other multi document application. The RadDocking control is the perfect control for covering this scenario. It has built-in support for tabbed Documents, hiding Panes, floating Windows, drag and drop, activation, save/load functionality, docking compasses etc. How can we combine all these amazing features in one working application? The next screenshot shows the final result of a possible IDE implementation:
Let’s begin.
Building the UI
The UI in the example contains two main layouts – the docking layout and a menu on top. Let’s add three main menu items on top for the main functionalities of an IDE, each of which has its own sub-menu items:
· File – contains sub-menu menu items for adding a new document at runtime and saving/loading the docking layout.
· View – contains information for all static defined panes in the layout.
· Window – contains information for all opened documents. Now, let’s create the initial RadDocking layout if there is no saved layout. Define three empty regions – one for the left, right and one for the bottom where we will place the panes. <
telerik:RadDocking
>
<
telerik:RadSplitContainer
MaxWidth
=
"600"
InitialPosition
=
"DockedLeft"
>
<
telerik:RadPaneGroup
Name
=
"leftGroup"
telerik:RadDocking.SerializationTag
=
"leftGroup"
>
</
telerik:RadPaneGroup
>
</
telerik:RadSplitContainer
>
<
telerik:RadSplitContainer
MaxWidth
=
"679"
InitialPosition
=
"DockedRight"
>
<
telerik:RadPaneGroup
x:Name
=
"rightGroup"
telerik:RadDocking.SerializationTag
=
"rightGroup"
>
</
telerik:RadPaneGroup
>
</
telerik:RadSplitContainer
>
<
telerik:RadSplitContainer
InitialPosition
=
"DockedBottom"
>
<
telerik:RadPaneGroup
x:Name
=
"bottomGroup"
telerik:RadDocking.SerializationTag
=
"bottomGroup"
>
</
telerik:RadPaneGroup
>
</
telerik:RadSplitContainer
>
</
telerik:RadDocking
>
ViewModel
We will need two kind of ViewModels – one for the MainWindow, and another one for the RadPane:
· The MainWindowViewModel controls some of the key features in the example. It contains:
o NewDocumentCommand – to create a new document at runtime
o SaveCommand – to save the docking layout
o LoadCommand – to loads the docking layout
o ObservableCollection of PaneViewModel – this is the data source for the RadDocking content
· The PaneViewModel contains properties which contains information about the panes. Also, using the PaneViewModel we can hide/show and activate the Panes through the menu.
Binding RadDocking with a Collection
How to bind RadDocking control with a Collection in the ViewModel? This question was asked many times since the control was created and we didn’t have one straight answer for that, until now! With the Q3 SP1 release of RadDocking we are introducing two key properties for the control:
· IEnumerable PanesSource – dependency property (which plays a similar role to the ItemsSource in the ItemsControls). It can be bound to a collection of data items or panes. For the purpose of the example, we will bind it to the ObservableCollection in the MainWindowViewModel.
· DockingPanesFactory DockingPanesFactory – filling up the RadDocking control with panes is the easy part. Where the new panes should be positioned? The DockingPanesFactory gives the answer to this question. More information can be found in our online documentation here.
So, let’s add some custom logic for creating and placing the Panes. If the new item which is added to the PanesSource is a document, а new RadDocumentPane is created, otherwise а RadPane should be created: protected
override
RadPane CreatePaneForItem(
object
item)
{
var viewModel = item
as
PaneViewModel;
if
(viewModel !=
null
)
{
var pane = viewModel.IsDocument ?
new
RadDocumentPane() :
new
RadPane();
pane.DataContext = item;
RadDocking.SetSerializationTag(pane, viewModel.Header);
if
(viewModel.ContentType !=
null
)
{
pane.Content = Activator.CreateInstance(viewModel.ContentType);
}
return
pane;
}
return
base
.CreatePaneForItem(item);
}
The logic for adding the newly created Pane is located in the AddPane override method. Simply reads the information from the PaneViewModel and adds it to the RadDocking control.
Save/Load layout
When saving the layout, RadDocking control generates an xml schema for its elements and their position, size and other properties. We need to set a SerializationTag for each Pane. Otherwise, each time when loading, a new Pane will be generated and we will lose the DataContext, which is not desirable. In MVVM scenario, the first thing to do is to save the ObservableCollection in the ViewModel, and after that the Docking layout itself. This is required because when reopening the application, the dynamic added items must be restored. When loading, we must load the saved ObservableCollection items and when all ViewModels are created and RadDocking is populated again, we can restore the layout with ease.
Compass restriction
In most modern IDEs the Panes (floating Windows) can only be docked in specific places in the application. In order to implement this feature we can use the compasses of the RadDocking control and add some restrictions for showing them. Let’s add some restriction in order to make our brand new IDE behave as Visual Studio does. For example, the documents can be tabbed near another documents or they can go floating, but docking them in one group with “Solution Explorer” shouldn’t be possible. To do that we need to handle the PreviewShowCompass event of the control and add the restriction logic depending on the dragged item and the drop target.
Menu
The main menu items we need are:
· File – contains the main commands for creating new document, saving and loading the layout
· View – contains all statically defined panes in the layout, such as ToolBox, Solution Explorer, Properties, etc. Checking the menu items hides or shows the panes using the MVVM pattern.
· Window – contains all opened documents from the File->New menu. Checking the menu items activates the views and bring them to front.
So, these are the main functionality which is covered the example. The source can be found here for WPF and SL as well.
We are really excited to present to you our vision of how the RadDocking control could and should be used when implementing the above described scenarios together in one project. The full source of the described example can be found in our online SDK repository here, you can download the entire repository as a zip file via this link.