I am trying to define the panes for the RadDocking control using its PaneSource binding to an ObservableCollection in a ViewModel and use the SaveLayout and LoadLayout methods to persist the layout of the RadDocking control between sessions. The first question I guess I have is “Should this work?” Does the RadDockingPanesSource and the Save and Load layout methods work together? Below are the important pieces I have created trying to put this together.
<
telerik:RadDocking
x:Name=”radDocking” PanesSource=”{Binding Panes}”>
<
telerik:RadSplitContainer
InitialPosition=”DockedLeft”>
<
telerik:RadPaneGroup
x:Name=”LeftPaneGroup” />
</
telerik:RadSplitContainer
>
<
telerik:RadSplitContainer
InitialPosition=”DockedRight”>
<
telerik:RadPaneGroup
x:Name=”RightPaneGroup” />
</
telerik:RadSplitContainer
>
<
telerik:RadSplitContainer
InitialPosition=”DockedBottom”>
<
telerik:RadPaneGroup
x:Name=”BottomPaneGroup” />
</
telerik:RadSplitContainer
>
<
telerik:RadDocking.DockingPanesFactory
>
<
local:MyDockingPanesFactory
/>
</
telerik:RadDocking.DockingPanesFactory
>
</
telerik:RadDocking
>
The XAML above shows the RadDocking control in my MainWindow.xaml file.
public class MyDockingPanesFactory : DockingPanesFactory {
protected override void AddPane(RadDocking radDocking, RadPane radPane) {
RadDocking.SetSerializationTag(radPane, ((DockPaneViewModel)radPane.DataContext).SerializationTag);
RadPaneGroup leftPaneGroup = radDocking.SplitItems.ToList().FirstOrDefault(i => i.Control.Name == “LeftPaneGroup”) as RadPaneGroup;
if (leftPaneGroup != null) {
if ((DockPaneViewModel)radPane.DataContext).InitialLocation == DockLocation.DockLeft) {
leftPaneGroup.Items.Add(radPane);
}
}
RadPaneGroup rightPaneGroup = radDocking.SplitItems.ToList().FirstOrDefault(i => i.Control.Name == “RightPaneGroup”) as RadPaneGroup;
if (rightPaneGroup != null) {
if ((DockPaneViewModel)radPane.DataContext).InitialLocation == DockLocation.DockRight) {
rightPaneGroup.Items.Add(radPane);
}
}
RadPaneGroup bottomPaneGroup = radDocking.SplitItems.ToList().FirstOrDefault(i => i.Control.Name == “BottomPaneGroup”) as RadPaneGroup;
if (bottomPaneGroup != null) {
if ((DockPaneViewModel)radPane.DataContext).InitialLocation == DockLocation.DockBottom) {
bottomPaneGroup.Items.Add(radPane);
}
}
}
protected override RadPane CreateRadPaneForItem(object item) {
if (item is DockPaneViewModel) {
return new RadPane() {
DataContext = item,
Content = item
};
} else {
throw new ArgumentException(“Invalid Type”);
}
}
}
The code above shows my DockingPaneFactory class and how is initially positions my ViewModels as RadPane(s). Notice in CreateRadPaneForItem I am setting the DataContext and the Content of the RadPane to the current DockPaneViewModel in the PanesSource. Setting the Content to the ViewModel will allow binding using a DataTemplate with a DataType defined (this is not shown). My DockPaneViewModel defines several notifiable properties like Header, IsActive, IsHidden, IsPinned, CanDockInDocumentHost, SerializationTag and defines its own InitialLocaiton that is used by the AddPane method in the DockingPaneFactory (above).
public abstract class DockPaneViewModel : ViewModelBase {
//Header, IsActive, IsHidden, IsPinned, CanDockInDocumentHost, SerializationTag
}
The code above is my DockPaneViewModel and which notifiable properties I have defined. These properties are bound their equivalent properties in the RadPane using a Style.
<
Application
… >
<
Application.Resources
>
<
ResourceDictionary
>
<
Style
TargetType=”{x:Type telerik:RadPane}” BasedOn=”{StaticResource RadPaneStyle}”>
<
Setter
Property=”Header” Value=”{Bindign Header,
Mode
=
TwoWay
}” />
<
Setter
Property=”IsActive” Value=”{Bindign IsActive,
Mode
=
TwoWay
}” />
<
Setter
Property=”IsHidden” Value=”{Bindign IsHidden,
Mode
=
TwoWay
}” />
<
Setter
Property=”IsPinned” Value=”{Bindign IsPinned,
Mode
=
TwoWay
}” />
<
Setter
Property=”CanDockInDocumentHost” Value=”{Bindign CanDockInDocumentHost,
Mode
=
TwoWay
}” />
</
Style
>
</
ResourceDictionary
>
</
Application.Resources
>
</
Application
>
The code above shows the custom RadPaneStyle that binds the properties in my DockPaneViewModel to the RadPane. This Style is defined in the Application Resources.
private void Application_Startup(object sender, StartupEventArgs e){
MainWindow mainWindow = new MainWindow();
mainWindow.DataContext = new MainWindowViewModel();
mainWindow.Show();
}
The code above shows how I am creating and showing the MainWindow and setting its DataContext.
public class MainWindowViewModel : ViewModelBase {
public ObservableCollection<
DockPaneViewModel
> Panes { get; private set; }
public MainWindowViewModel(){
Panes = new ObservableCollection<
DockPaneViewModel
>(
new ViewModel1(),new ViewModel2(),new ViewModel3()
);
}
}
The code above is my MainWindowViewModel which shows the ObservableColleciton of DockViewModels. I am just showing a hard-coded set of three ViewModels being added to the Panes collection. In the real project I am using an IOC container to create all classes that inherit from DockPaneViewModel which get added to the Panes collection.
private void RadRibbonWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
using (System.IO.Stream stream = new System.IO.FileStream(App.LayoutSettings, System.IO.FileMode.Create)){
this.radDocking.SaveLayout(stream);
}
}
protected override void OnSourceInitialized(EventArgs e) {
using (System.IO.Stream stream = new System.IO.FileStream(App.LayoutSettings, System.IO.FileMode.Open)) {
this.radDocking.LoadLayout(stream);
}
}
Lastly the code above shows closing event and the override for the OnSourceInitialized. This is where I am saving and loading the layout XML file for the RadDocking control. The XML file that gets created does not seem to have any IsPinned properties. At first I thought I forgot to add IsPinned as a notifiable property to the DockPaneViewModel but that was not the case. I also thought I forgot to add IsPinned to the XAML Style that binds the properties between the RadPane and the DockPaneViewModel but that was not the case either.
I am not exactly sure why this is not working. I am not 100% sure if the RadDocking.PanesSource can be used with the SaveLayout and LoadLayout methods. If anyone could give me some direction or advice it would be greatly appreciated. I am not sure what to try next.