Features
- Support MVVM with Prism
- Supports ViewModel First or ViewFirst Approach
- Supports styling RadPane in xaml rather than DockingPansFactory
- Code RadDocking – SourceCode
The XAML
- Defiine the region names at RadPaneGroup level
- Set Rad Panel Style via ItemContainerStyle
- Bind Header property of RadPane with Title Property in View Model
<Window.Resources> <Style x:Key="RadPaneFactoryStyle" TargetType="{x:Type telerik:RadPane}"> <Setter Property="Header" Value="{Binding Title}"/> </Style> </Window.Resources> <Grid> <telerikDocking:RadDocking> <telerikDocking:RadDocking.DocumentHost> <telerikDocking:RadSplitContainer > <telerikDocking:RadPaneGroup regions:RegionManager.RegionName="MainRegion" ItemContainerStyle="{StaticResource RadPaneFactoryStyle}" > </telerikDocking:RadPaneGroup> </telerikDocking:RadSplitContainer> </telerikDocking:RadDocking.DocumentHost> <telerikDocking:RadSplitContainer InitialPosition="DockedRight"> <telerikDocking:RadPaneGroup regions:RegionManager.RegionName="MainRegion1" > </telerikDocking:RadPaneGroup> </telerikDocking:RadSplitContainer> </telerikDocking:RadDocking> </Grid>
Configure Region Adapter Mappings in Bootstrap
protected override RegionAdapterMappings ConfigureRegionAdapterMappings() { var mappings = base.ConfigureRegionAdapterMappings(); mappings.RegisterMapping(typeof(RadPaneGroup), this.Container.Resolve<RadPaneGroupRegionAdapter>()); return mappings; }
Define the RadPaneGroup RegionAdapter
Behavior public class RadPaneGroupRegionAdapter : RegionAdapterBase<RadPaneGroup> { public RadPaneGroupRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory) { } protected override void Adapt(IRegion region, RadPaneGroup regionTarget) { var docking = regionTarget.ParentOfType<RadDocking>(); if (docking.DockingPanesFactory == null) { docking.DockingPanesFactory = new CustomDockingPanesFactory(); } var store = DocumentsStoreAttachment.GetPanesStore(docking); if (store == null) { store = new PanesStore(); DocumentsStoreAttachment.SetPanesStore(docking, store); BindingOperations.SetBinding( docking, RadDocking.PanesSourceProperty, new Binding("PanesSource") { Source = store }); } } protected override IRegion CreateRegion() { return new SingleActiveRegion(); } protected override void AttachBehaviors(IRegion region, RadPaneGroup regionTarget) { if (region == null) throw new System.ArgumentNullException("region"); var docking = regionTarget.ParentOfType<RadDocking>(); // Add the behavior that syncs the items source items with the rest of the items region.Behaviors.Add(RadPaneGroupSyncBehavior.BehaviorKey, new RadPaneGroupSyncBehavior() { HostControl = regionTarget, Docking = docking }); base.AttachBehaviors(region, regionTarget); } private class PanesStore { public readonly ObservableCollection<object> Panes = new ObservableCollection<object>(); ReadOnlyObservableCollection<object> _readonlyDocumentsList; public ReadOnlyObservableCollection<object> PanesSource { get { return _readonlyDocumentsList ?? (_readonlyDocumentsList = new ReadOnlyObservableCollection<object>(Panes)); } } } private static class DocumentsStoreAttachment { public static readonly DependencyProperty PanesStoreProperty = DependencyProperty.RegisterAttached( "PanesStore", typeof(PanesStore), typeof(DocumentsStoreAttachment), new PropertyMetadata(null) ); public static void SetPanesStore(UIElement element, PanesStore value) { element.SetValue(PanesStoreProperty, value); } public static PanesStore GetPanesStore(UIElement element) { return (PanesStore)element.GetValue(PanesStoreProperty); } } private class CustomDockingPanesFactory : DockingPanesFactory { public RadPaneGroup ActiveGroup { get; internal set; } protected override void AddPane(RadDocking radDocking, RadPane pane) { var group = ActiveGroup; pane.SetValue(RadPane.HeaderProperty, DependencyProperty.UnsetValue); var style = group.ItemContainerStyle; if (style != null) { pane.SetValue(RadPane.StyleProperty, style); } group?.Items.Add(pane); } } private class RadPaneGroupSyncBehavior : RegionBehavior, IHostAwareRegionBehavior { public static readonly string BehaviorKey = "RadPaneGroupSyncBehavior"; private bool _updatingActiveViewsInManagerActiveContentChanged; private RadPaneGroup _radPaneGroup; private PanesStore _documentStore; public DependencyObject HostControl { get { return _radPaneGroup; } set { _radPaneGroup = value as RadPaneGroup; } } public RadDocking Docking { get; internal set; } /// <summary> /// Starts to monitor the <see cref="IRegion"/> to keep it in synch with the items of the <see cref="HostControl"/>. /// </summary> protected override void OnAttach() { bool itemsSourceIsSet = _radPaneGroup.ItemsSource != null; if (itemsSourceIsSet) { throw new InvalidOperationException(); } SynchronizeItems(); Docking.ActivePaneChanged += ManagerActiveContentChanged; Region.ActiveViews.CollectionChanged += ActiveViews_CollectionChanged; Region.Views.CollectionChanged += Views_CollectionChanged; Docking.Close += _dockingManager_DocumentClosed; } private void _dockingManager_DocumentClosed(object sender, StateChangeEventArgs e) { foreach (var pane in e.Panes) { if (Region.Views.Contains(pane.Content)) { Region.Remove(pane.Content); } } } private void Views_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { int startIndex = e.NewStartingIndex; foreach (var newItem in e.NewItems) { var panesFactory = ((CustomDockingPanesFactory)Docking.DockingPanesFactory); panesFactory.ActiveGroup = _radPaneGroup; _documentStore.Panes.Insert(0, newItem); } } else if (e.Action == NotifyCollectionChangedAction.Remove) { foreach (object oldItem in e.OldItems) { _documentStore.Panes.Remove(oldItem); } } } private void SynchronizeItems() { var store = DocumentsStoreAttachment.GetPanesStore(Docking); _documentStore = store; foreach (object view in Region.Views) { ((CustomDockingPanesFactory)Docking.DockingPanesFactory).ActiveGroup = _radPaneGroup; _documentStore.Panes.Insert(0, view); } } private void ActiveViews_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (_updatingActiveViewsInManagerActiveContentChanged) { return; } if (e.Action == NotifyCollectionChangedAction.Add) { if (Docking.ActivePane != null && Docking.ActivePane != e.NewItems[0] && Region.ActiveViews.Contains(Docking.ActivePane.Content)) { Region.Deactivate(Docking.ActivePane.Content); } var pane = Docking.Panes.FirstOrDefault(x => x.Content.Equals(e.NewItems[0])); Docking.ActivePane = pane; } else if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems.Contains(Docking.ActivePane)) { Docking.ActivePane = null; } } private void ManagerActiveContentChanged(object sender, EventArgs e) { try { _updatingActiveViewsInManagerActiveContentChanged = true; if (Docking.Equals(sender)) { var activePane = Docking.ActivePane; if (activePane != null) { var activeViews = Region.ActiveViews.Where(it => it != activePane.Content).ToList(); foreach (var item in activeViews) { Region.Deactivate(item); } if (Region.Views.Contains(activePane.Content) && !Region.ActiveViews.Contains(activePane.Content)) { Region.Activate(activePane.Content); } } } } finally { _updatingActiveViewsInManagerActiveContentChanged = false; } } } }