RadDocking With Prism + Mvvm

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;
 }
 }

 }
 }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s