This is a migrated thread and some comments may be shown as answers.

Caliburn Micro Docking Implementation?

33 Answers 361 Views
Docking
This is a migrated thread and some comments may be shown as answers.
Steve
Top achievements
Rank 1
Steve asked on 22 Jul 2011, 09:34 PM
Has anyone succeeded in creating a docking implementation that used Caliburn Micro? What I am trying to do is have a docking shell where the only thing it knows about is a toolbox pinned on the side and dynamically loads document panes from external XAPs. The dynamically loading and stuff is easy but I am having trouble figuring out what needs to happen to allow Caliburn to handle the dynamic view creation and have them as the content of dynamically created panes.

I have the Telerik conventions for Caliburn Micro and I'm looking at the RadTabControl changes to allow the conventions to work but docking is a lot more complicated so I am not sure where to begin.

Any help would be greatly appreciated.

Steve

33 Answers, 1 is accepted

Sort by
0
Steve
Top achievements
Rank 1
answered on 26 Jul 2011, 03:39 PM
I was able to get it working. I don't think what I have done is 100% ideal but it is good enough for now to see results and can hopefully be tweaked in the future to be better. The key is that CM has to be told to explicitly about the RadPane.

RadPane pane = new RadPane();
Caliburn.Micro.View.SetModel(pane, viewModel);

0
Marc
Top achievements
Rank 1
answered on 06 Oct 2011, 02:59 PM
Hi Steve,

thank you for sharing your ideas. Do you think it's possible to attach the source code of what you did to make Caliburn.Micro's navigation infrastructure work with RadDocking. This would be really helpful for me and probably others as well.


Thanks in advance,
Stephan
0
Steve
Top achievements
Rank 1
answered on 19 Oct 2011, 02:46 PM
Stephan,

Sorry I didn't get back to you till now. Here is some of the code. There are some bugs and problems with it but it at least proves the concept. I haven't spent any more time on this piece since I was able to get it to at least partially work. Let me know if you have any questions about it and I'll try to respond quicker :).

Here is the view model. You may have to substitute your MEF loading but the idea is here.
[Export(typeof(DockingShellHostViewModel)), PartCreationPolicy(CreationPolicy.NonShared)]
public class DockingShellHostViewModel : Conductor<IModule>.Collection.AllActive
{
   #region Members
 
   private ModuleDefinition m_moduleDefinitionToLoad;
 
   #endregion
 
   #region Constructor
 
   [ImportingConstructor]
   public DockingShellHostViewModel(
      ICompositionCatalogService a_catalogService)
   {
      CatalogService = a_catalogService;
 
      ModuleRadPaneGroups = new ObservableCollection<RadPaneGroup>();
   }
 
   #endregion
 
   #region Properties
 
   private ICompositionCatalogService CatalogService { get; set; }
 
   public ObservableCollection<RadPaneGroup> ModuleRadPaneGroups { get; set; }
 
   #endregion
 
   #region Methods
 
   public void LoadModule(ModuleDefinition a_moduleDefinition)
   {
      m_moduleDefinitionToLoad = a_moduleDefinition;
      IdeaBlade.EntityModel.Coroutine.Start(LoadModule);
   }
 
   private IEnumerable<INotifyCompleted> LoadModule()
   {
      yield return CatalogService.AddXap(m_moduleDefinitionToLoad.XapName);
 
      object returnModule = CatalogService.GetInstance(typeof(IModule), m_moduleDefinitionToLoad.Module.ToString(), CreationPolicy.NonShared);
      if (returnModule != null)
      {
         if (ModuleRadPaneGroups.Count == 0)
         {
            RadPaneGroup group = new RadPaneGroup();
            ModuleRadPaneGroups.Add(group);
         }
 
         RadPane pane = new RadPane();
         pane.Header = m_moduleDefinitionToLoad.Title;
 
         // This line tells Caliburn Micro to find the associated view and assign it as the content of the RadPane
         // instead of the view model. This is the glue that makes it all work.
         Caliburn.Micro.View.SetModel(pane, returnModule);
         // Add the pane to the collection so that it is displayed in the UI.
         ModuleRadPaneGroups[0].AddItem(pane, Telerik.Windows.Controls.Docking.DockPosition.Center);
 
         pane.Focus();
         pane.IsSelected = true;
 
         // Activate the item so that it's life cycle is started.
         this.ActivateItem(returnModule as IModule);
      }
   }
 
   #endregion
}

Here is the view. Nothing to it.

             x:Class="..."
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:cal="http://www.caliburnproject.org"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400">
 
   <UserControl.Resources>
      <ng:ImageWrapper x:Key="ImageWrapper" />
      <ng:InvertBoolConverter x:Key="InvertBoolConverter" />
   </UserControl.Resources>
 
   <Grid x:Name="LayoutRoot"
         Background="White">
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <telerik:RadMenu>
         <telerik:RadMenuItem Header="View">
         </telerik:RadMenuItem>
      </telerik:RadMenu>
      <telerik:RadDocking Grid.Row="1">
         <telerik:RadDocking.DocumentHost>
            <telerik:RadSplitContainer ItemsSource="{Binding ModuleRadPaneGroups}">
            </telerik:RadSplitContainer>
         </telerik:RadDocking.DocumentHost>
      </telerik:RadDocking>
   </Grid>
</UserControl>

Steve
0
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 03:24 PM
Thank you Steve,

meanwhile I wrote my own implementation. It basically acts as a mediator between a given IConductor and a (optionally given) RadDocking control using the respective events of each one and creating necessary stuff like panes etc. on the fly.

However, thank you for answering.

Cheers,
Stephan
0
Steve
Top achievements
Rank 1
answered on 19 Oct 2011, 03:27 PM
Stephan,

Glad you were able to get something together. Sounds like the approach you took was a lot better. Would you be able to expound on the idea or post code?

Thanks,
Steve
0
Accepted
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 03:30 PM
There you go:

public class DockManager : IDockManager
    {
        private IConductActiveItem _conductor;
        private RadDocking _dock;
 
        private bool _activatedFromViewModel;
        private bool _actuallyClosing;
        private bool _deactivateFromViewModel;
        private bool _deactivatingFromView;
 
 
        public void Link(IConductor conductor, FrameworkElement dock = null)
        {
            if (_conductor != null || _dock != null)
            {
                throw new InvalidOperationException("Dock manager is already linked");
            }
 
            _conductor = conductor as IConductActiveItem;
            _dock = dock as RadDocking ?? FindDock();
 
            if (_conductor == null || _dock == null)
            {
                throw new InvalidOperationException("Invalid conductor or docking control");
            }
 
            _conductor.ActivationProcessed += OnActivationProcessed;
            _dock.ActivePaneChanged += OnActivePaneChanged;
            _dock.PreviewClose += OnPreviewClose;
            _dock.Close += OnClose;
        }
 
 
        protected virtual void OnActivationProcessed(object s, ActivationProcessedEventArgs e)
        {
            if (!e.Success)
            {
                return;
            }
 
            object viewModel = e.Item;
            RadPane pane = FindPane(viewModel);
            if (pane == null)
            {
                _activatedFromViewModel = true;
 
                pane = CreatePane(viewModel);
                AttachPane(viewModel, pane);
 
                var deactivatable = viewModel as IDeactivate;
                if (deactivatable != null)
                {
                    deactivatable.Deactivated += OnDeactivated;
                }
            }
 
            _dock.ActivePane = pane;
        }
 
 
        protected virtual void OnActivePaneChanged(object s, ActivePangeChangedEventArgs e)
        {
            if (_activatedFromViewModel)
            {
                _activatedFromViewModel = false;
                return;
            }
 
            RadPane pane = e.NewPane;
            if (pane == null)
            {
                return;
            }
 
            _conductor.ActivateItem(pane.DataContext);
        }
 
 
        protected virtual void OnDeactivated(object s, DeactivationEventArgs e)
        {
            if (!e.WasClosed)
            {
                return;
            }
 
            ((IDeactivate) s).Deactivated -= OnDeactivated;
 
            if (_deactivatingFromView)
            {
                return;
            }
 
            _deactivateFromViewModel = true;
            RemovePane(FindPane(s));
            _deactivateFromViewModel = false;
        }
 
 
        protected virtual void OnPreviewClose(object s, StateChangeEventArgs e)
        {
            RadPane pane = e.Panes.FirstOrDefault();
            if (pane == null)
            {
                return;
            }
 
            var guard = pane.DataContext as IGuardClose;
            if (guard == null)
            {
                return;
            }
 
            if (e.Handled)
            {
                return;
            }
 
            if (_actuallyClosing)
            {
                _actuallyClosing = false;
                return;
            }
 
            bool runningAsync = false;
            bool shouldEnd = false;
 
            guard.CanClose(canClose =>
            {
                Execute.OnUIThread(() =>
                {
                    if (runningAsync && canClose)
                    {
                        _actuallyClosing = true;
                        pane.IsHidden = true;
                    }
                    else
                    {
                        e.Handled = !canClose;
                    }
 
                    shouldEnd = true;
                });
            });
 
            if (shouldEnd)
            {
                return;
            }
 
            e.Handled = true;
            runningAsync = true;
        }
 
 
        protected virtual void OnClose(object s, StateChangeEventArgs e)
        {
            RadPane pane = e.Panes.FirstOrDefault();
            if (pane == null)
            {
                return;
            }
 
            var deactivatable = pane.DataContext as IDeactivate;
            if (deactivatable == null)
            {
                return;
            }
 
            if (_deactivateFromViewModel)
            {
                return;
            }
 
            _deactivatingFromView = true;
            RemovePane(pane);
            deactivatable.Deactivate(true);
            _deactivatingFromView = false;
        }
 
 
        protected virtual RadDocking FindDock()
        {
            return Application.Current.RootVisual.FindChildByType<RadDocking>();
        }
 
 
        protected virtual RadPane FindPane(object viewModel)
        {
            return _dock.Panes.FirstOrDefault(p => p.DataContext == viewModel);
        }
 
 
        protected virtual RadPane CreatePane(object viewModel)
        {
            RadPane pane = EnsurePane(viewModel, ViewLocator.LocateForModel(viewModel, null, null));
            ViewModelBinder.Bind(viewModel, pane, null);
 
            var haveDisplayName = viewModel as IHaveDisplayName;
            if (haveDisplayName != null && !ConventionManager.HasBinding(pane, HeaderedContentControl.HeaderProperty))
            {
                pane.Header = new DisplayDataControl();
            }
 
            return pane;
        }
 
 
        protected virtual RadPane EnsurePane(object viewModel, object view)
        {
            var pane = view as RadPane;
 
            if (pane == null)
            {
                pane = new RadPane { DataContext = viewModel, Content = view };
                pane.SetValue(View.IsGeneratedProperty, true);
            }
 
            return pane;
        }
 
 
        protected virtual void AttachPane(object viewModel, RadPane pane)
        {
            DockState? dockState = GetDockState(viewModel);
 
            RadSplitContainer splitContainer;
            if (dockState == null)
            {
                splitContainer = _dock.DocumentHost as RadSplitContainer;
                if (splitContainer == null)
                {
                    splitContainer = new RadSplitContainer();
                    splitContainer.SetValue(View.IsGeneratedProperty, true);
                    _dock.DocumentHost = splitContainer;
                }
            }
            else
            {
                splitContainer = _dock.Items.OfType<RadSplitContainer>().FirstOrDefault(
                    x => x.GetValue(RadDocking.DockStateProperty) as DockState? == dockState);
                if (splitContainer == null)
                {
                    splitContainer = new RadSplitContainer { InitialPosition = dockState.Value };
                    splitContainer.SetValue(View.IsGeneratedProperty, true);
                    _dock.Items.Add(splitContainer);
                }
            }
 
            RadPaneGroup paneGroup = splitContainer.Items.OfType<RadPaneGroup>().FirstOrDefault();
            if (paneGroup == null)
            {
                paneGroup = new RadPaneGroup { IsContentPreserved = true };
                paneGroup.SetValue(View.IsGeneratedProperty, true);
                paneGroup.SelectedItemRemoveBehaviour = SelectedItemRemoveBehaviour.SelectNone;
                splitContainer.Items.Add(paneGroup);
            }
 
            paneGroup.AddItem(pane, DockPosition.Center);
        }
 
 
        protected virtual void RemovePane(RadPane pane)
        {
            if (pane == null)
            {
                return;
            }
 
            RadPaneGroup paneGroup = pane.PaneGroup;
            pane.RemoveFromParent();
            if (paneGroup == null || paneGroup.HasItems)
            {
                return;
            }
 
            RadSplitContainer splitContainer = paneGroup.ParentContainer;
            paneGroup.RemoveFromParent();
            if (splitContainer == null || splitContainer.HasItems)
            {
                return;
            }
 
            if (splitContainer.IsInDocumentHost)
            {
                _dock.DocumentHost = null;
            }
            else
            {
                _dock.Items.Remove(splitContainer);
            }
        }
 
 
        protected virtual DockState? GetDockState(object viewModel)
        {
            if (viewModel is IHavePaneSettings)
            {
                var paneSettings = (IHavePaneSettings) viewModel;
 
                switch (paneSettings.InitialState)
                {
                    case PaneState.DockedLeft:
                        return DockState.DockedLeft;
                    case PaneState.DockedTop:
                        return DockState.DockedTop;
                    case PaneState.DockedRight:
                        return DockState.DockedRight;
                    case PaneState.DockedBottom:
                        return DockState.DockedBottom;
                }
            }
            return null;
        }
    }
0
Steve
Top achievements
Rank 1
answered on 19 Oct 2011, 04:04 PM
Thank you Stephan. That works like a charm. It will be a great example for extending CM and making it work in a real world app.

Much appreciated,
Steve
0
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 05:03 PM
Thank you Steve,

maybe I'll send this to the Caliburn.Micro community someday.

Two things I'd like to mention:
- When closing the selected pane via UI (not via VM) the RadDocking control always selects the first pane (not what I actually want) even though I set the according behaviour to select-none. More about this here: http://www.telerik.com/community/forums/silverlight/docking/support-for-selecteditemremovebehaviour.aspx
- I never tested the code in OnPreviewClosed when ExecuteOnUIThread runs asynchronously. In case you ever do that, let me know what happened.

Cheers,
Stephan

0
Derek
Top achievements
Rank 1
answered on 19 Oct 2011, 07:30 PM
Stephen, can you post the IDockManager & IHavePaneSettings interfaces?
0
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 07:33 PM
Sure. They're rather simple and generic.

public interface IDockManager
    {
        void Link(IConductor conductor, FrameworkElement dock = null);
    }

public interface IHavePaneSettings
    {
        PaneState InitialState { get; }
    }
 
 
    public enum PaneState
    {
        DockedCenter,
        DockedLeft,
        DockedTop,
        DockedRight,
        DockedBottom
    }
0
Derek
Top achievements
Rank 1
answered on 19 Oct 2011, 07:35 PM
Thanks, I guess I only needed IDocmanager.  Nice work on this.
0
Steve
Top achievements
Rank 1
answered on 19 Oct 2011, 07:38 PM
You could simply not implement the interface. I didn't.

Stephan, I would definitely submit it to CM people. It would be nice if Telerik would compile a group of functionality devoted to working with CM. I have found tidbits spread around the forums and other places like making the RadWindow work, conventions, etc.
0
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 07:41 PM
Yes, I know. I probably found the same stuff. But unfortunately nothing that fit my needs.
And yes, I will submit this to the CM community in some way. Thank you for your interest.
0
Derek
Top achievements
Rank 1
answered on 19 Oct 2011, 07:46 PM
Send it to Rob. rob.eisenberg at gmail.com
0
Marc
Top achievements
Rank 1
answered on 19 Oct 2011, 07:51 PM
To the boss himself ???
0
Derek
Top achievements
Rank 1
answered on 19 Oct 2011, 08:01 PM
Yeah, or post it in the forum.

related:http://caliburnmicro.codeplex.com/discussions/231809
0
Michele
Top achievements
Rank 2
answered on 07 Nov 2011, 11:02 AM
Hello,
I'm new to CM and Docking..... I've tried to paste in a class
[Export(typeof(DockingShellHostViewModel)), PartCreationPolicy(CreationPolicy.NonShared)]
public class DockingShellHostViewModel
...

but I got an unknown type for ModuleDefinition and IModule ... what am I missing?
0
Steve
Top achievements
Rank 1
answered on 07 Nov 2011, 02:00 PM
Paolo,

I wouldn't use the code that I posted. It is not ideal. Stephan's implementation is a lot better and uses CM to the max.

Just so you know, those classes are specific to my implementation. You can replace IModule with whatever interface you are using for MEF. I am dynamically downloading XAPs and modules so they implement IModule. ModuleDefinition is simply a class that has information about the IModule. ModuleDefinition is used because the XAP might need to be downloaded.

Not sure if that is clear enough for you.

Steve
0
Derek
Top achievements
Rank 1
answered on 07 Nov 2011, 06:00 PM
I implemented this a little differently.  I followed an example from the forums combined with the WindowManager impl.
https://gist.github.com/1345512

edit: I should add, I used Stephen's excellent example and a post from the CM forums as well.
0
Michele
Top achievements
Rank 2
answered on 07 Nov 2011, 06:05 PM
Hello Derek,
the implementation you've got is a replacement of RadDocking or it's a must to implement in order to use caliburn & raddocking?
Thanks
0
Derek
Top achievements
Rank 1
answered on 07 Nov 2011, 06:12 PM
it doesn't replace RadDocking.  It lets you use RadDocking like WindowManager.
0
Marc
Top achievements
Rank 1
answered on 08 Nov 2011, 07:00 PM
hi guys,

i just wanted to let you know that i really sent my code to rob eisenberg who kindly reviewed it. he suggested to send it to the author of Caliburn.Micro.Telerik which i tried (see here). additionally i posted it to the CM forum (see here). and now, for the sake of completeness here. below is my current version (custom stuff stripped out). just in case any of you use my previous version: please update because there is a bug (on close an item must be removed through the conductor which in turn deactivates it if possible - previously the items itself got deactivated directly and therefore not removed from the conductor's list).

if anybody finds another bug - please let me know...

regards,
stephan


// A dock manager acts as a mediator between a conductor and an optionally
// given docking control which is typically found in the view of the conductor.
// Even though the interface is pretty simple and generic, it might suffice many
// if not all (?) docking libraries.
public interface IDockManager
{
    void Link(IConductor conductor, FrameworkElement dock = null);
}
 
// A view model may wish to implement a dedicated interface (probably dependent
// on the functionality of the concrete docking library) like this to express
// certain docking relevant preferences which can be addressed by the docking manager.
public interface IHaveDockPreferences
{
    DockingState InitialState { get; }
}
 
public enum DockingState
{
    DockedCenter,
    DockedLeft,
    DockedTop,
    DockedRight,
    DockedBottom
}
 
// A dock manager is usually injected in the according conductor view model.
// Here we omit the concrete dock control and let the dock manager find it in the
// visual tree. This of course requires that the Link-method is called after the
// conductor's view (which hopefully contains the docking control) is loaded.
public class WorkspaceViewModel : Conductor<object>.Collection.OneActive
{
    [Import]
    public IDockManager DockManager { get; set; }
 
    protected override void OnViewLoaded(object view)
    {
        base.OnViewLoaded(view);
         
        DockManager.Link(this);
 
        ActivateItem(SomePlainViewModel);
        ActivateItem(SomeOtherViewModelWhichImplementsIHaveDockPreferences);
         
        ...
    }
     
    ...
}
 
// My implementation of IDockManager for Telerik's RadDocking (SL). It basically acts as a
// mediator between a given IConductor (IConductActiveItem in this case) and an optionally
// given docking control (RadDocking in this case) using the respective events of each one
// and creating/removing necessary stuff like panes etc. on the fly.
[Export(typeof(IDockManager))]
public class DockManager : IDockManager
{
    private IConductActiveItem _conductor;
    private RadDocking _dock;
 
    private bool _activatedFromViewModel;
    private bool _actuallyClosing;
    private bool _deactivatingFromView;
 
 
    public void Link(IConductor conductor, FrameworkElement dock = null)
    {
        if (_conductor != null || _dock != null)
        {
            throw new InvalidOperationException("Dock manager is already linked");
        }
 
        _conductor = conductor as IConductActiveItem;
        _dock = dock as RadDocking ?? FindDock();
 
        if (_conductor == null || _dock == null)
        {
            throw new InvalidOperationException("Invalid conductor or docking control");
        }
 
        _conductor.ActivationProcessed += OnActivationProcessed;
        _dock.ActivePaneChanged += OnActivePaneChanged;
        _dock.PreviewClose += OnPreviewClose;
        _dock.Close += OnClose;
    }
 
 
    protected virtual void OnActivationProcessed(object s, ActivationProcessedEventArgs e)
    {
        if (!e.Success)
        {
            return;
        }
 
        object viewModel = e.Item;
        RadPane pane = FindPane(viewModel);
        if (pane == null)
        {
            _activatedFromViewModel = true;
 
            pane = CreatePane(viewModel);
            AttachPane(viewModel, pane);
 
            var deactivatable = viewModel as IDeactivate;
            if (deactivatable != null)
            {
                deactivatable.Deactivated += OnDeactivated;
            }
        }
 
        _dock.ActivePane = pane;
    }
 
 
    protected virtual void OnActivePaneChanged(object s, ActivePangeChangedEventArgs e)
    {
        if (_activatedFromViewModel)
        {
            _activatedFromViewModel = false;
            return;
        }
 
        RadPane pane = e.NewPane;
        if (pane == null)
        {
            return;
        }
 
        _conductor.ActivateItem(pane.DataContext);
    }
 
 
    protected virtual void OnDeactivated(object s, DeactivationEventArgs e)
    {
        if (!e.WasClosed)
        {
            return;
        }
 
        ((IDeactivate) s).Deactivated -= OnDeactivated;
 
        if (_deactivatingFromView)
        {
            return;
        }
 
        RemovePane(FindPane(s));
    }
 
 
    protected virtual void OnPreviewClose(object s, StateChangeEventArgs e)
    {
        RadPane pane = e.Panes.FirstOrDefault();
        if (pane == null)
        {
            return;
        }
 
        var guard = pane.DataContext as IGuardClose;
        if (guard == null)
        {
            return;
        }
 
        if (e.Handled)
        {
            return;
        }
 
        if (_actuallyClosing)
        {
            _actuallyClosing = false;
            return;
        }
 
        bool runningAsync = false;
        bool shouldEnd = false;
 
        guard.CanClose(canClose =>
        {
            Execute.OnUIThread(() =>
            {
                if (runningAsync && canClose)
                {
                    _actuallyClosing = true;
                    pane.IsHidden = true;
                }
                else
                {
                    e.Handled = !canClose;
                }
 
                shouldEnd = true;
            });
        });
 
        if (shouldEnd)
        {
            return;
        }
 
        e.Handled = true;
        runningAsync = true;
    }
 
 
    protected virtual void OnClose(object s, StateChangeEventArgs e)
    {
        RadPane pane = e.Panes.FirstOrDefault();
        if (pane == null)
        {
            return;
        }
 
        _deactivatingFromView = true;
        _conductor.CloseItem(pane.DataContext);
        RemovePane(pane);
        _deactivatingFromView = false;
    }
 
 
    protected virtual RadDocking FindDock()
    {
        return Application.Current.RootVisual.FindChildByType<RadDocking>();
    }
 
 
    protected virtual RadPane FindPane(object viewModel)
    {
        return _dock.Panes.FirstOrDefault(pane => pane.DataContext == viewModel);
    }
 
 
    protected virtual RadPane CreatePane(object viewModel)
    {
        RadPane pane = EnsurePane(viewModel, ViewLocator.LocateForModel(viewModel, null, null));
        ViewModelBinder.Bind(viewModel, pane, null);
 
        var haveDisplayName = viewModel as IHaveDisplayName;
        if (haveDisplayName != null && !ConventionManager.HasBinding(pane, HeaderedContentControl.HeaderProperty))
        {
            var binding = new Binding("DisplayName") { Mode = BindingMode.TwoWay };
            pane.SetBinding(HeaderedContentControl.HeaderProperty, binding);
        }
 
        return pane;
    }
 
 
    protected virtual RadPane EnsurePane(object viewModel, object view)
    {
        var pane = view as RadPane;
 
        if (pane == null)
        {
            pane = new RadPane { DataContext = viewModel, Content = view };
            pane.SetValue(View.IsGeneratedProperty, true);
        }
 
        return pane;
    }
 
 
    protected virtual void AttachPane(object viewModel, RadPane pane)
    {
        DockState? dockState = GetDockState(viewModel);
 
        RadSplitContainer splitContainer;
        if (dockState == null)
        {
            splitContainer = _dock.DocumentHost as RadSplitContainer;
            if (splitContainer == null)
            {
                splitContainer = new RadSplitContainer();
                splitContainer.SetValue(View.IsGeneratedProperty, true);
                _dock.DocumentHost = splitContainer;
            }
        }
        else
        {
            splitContainer = _dock.Items.OfType<RadSplitContainer>().FirstOrDefault(
                container => container.GetValue(RadDocking.DockStateProperty) as DockState? == dockState);
            if (splitContainer == null)
            {
                splitContainer = new RadSplitContainer { InitialPosition = dockState.Value };
                splitContainer.SetValue(View.IsGeneratedProperty, true);
                _dock.Items.Add(splitContainer);
            }
        }
 
        RadPaneGroup paneGroup = splitContainer.Items.OfType<RadPaneGroup>().FirstOrDefault();
        if (paneGroup == null)
        {
            paneGroup = new RadPaneGroup { IsContentPreserved = true };
            paneGroup.SetValue(View.IsGeneratedProperty, true);
            paneGroup.SelectedItemRemoveBehaviour = SelectedItemRemoveBehaviour.SelectNone;
            splitContainer.Items.Add(paneGroup);
        }
 
        paneGroup.AddItem(pane, DockPosition.Center);
    }
 
 
    protected virtual void RemovePane(RadPane pane)
    {
        if (pane == null)
        {
            return;
        }
 
        RadPaneGroup paneGroup = pane.PaneGroup;
        pane.RemoveFromParent();
        if (paneGroup == null || paneGroup.HasItems)
        {
            return;
        }
 
        RadSplitContainer splitContainer = paneGroup.ParentContainer;
        paneGroup.RemoveFromParent();
        if (splitContainer == null || splitContainer.HasItems)
        {
            return;
        }
 
        if (splitContainer.IsInDocumentHost)
        {
            _dock.DocumentHost = null;
        }
        else
        {
            _dock.Items.Remove(splitContainer);
        }
    }
 
 
    protected virtual DockState? GetDockState(object viewModel)
    {
        if (viewModel is IHaveDockPreferences)
        {
            var dockPreferences = (IHaveDockPreferences) viewModel;
 
            switch (dockPreferences.InitialState)
            {
                case DockingState.DockedLeft:
                    return DockState.DockedLeft;
                case DockingState.DockedTop:
                    return DockState.DockedTop;
                case DockingState.DockedRight:
                    return DockState.DockedRight;
                case DockingState.DockedBottom:
                    return DockState.DockedBottom;
            }
        }
        return null;
    }
}

0
Chuck
Top achievements
Rank 1
answered on 16 Nov 2011, 10:22 PM
Stephan,
This worked like a charm for us. Thanks for posting!
0
Michele
Top achievements
Rank 2
answered on 28 Nov 2011, 09:46 AM
Hello to everybody,
now that I've created my single models I wish to attach them at load on the workspace but I've no idea about adding them... my workspaceviewmodel (the one that's load from the bootstrapper and that holds a reference to DockManager is defined as )

[Export]
   public class WorkspaceViewModel : Conductor<object>.Collection.OneActive
   {
       [Import]
       public IDockManager DockManager { get; set; }
 
       private IWindowManager _manager;
       private IApplicationRepository _repository;
 
       [ImportingConstructor]
       public WorkspaceViewModel(IApplicationRepository repository, IWindowManager manager)
       {
           base.DisplayName = "myapp";
           _manager = manager;
           _repository = repository;
       }
 
 
       protected override void OnViewLoaded(object view)
       {
           base.OnViewLoaded(view);
 
           DockManager.Link(this);
 
           UserMessagesViewModel model = new UserMessagesViewModel(_repository);
 
           ActivateItem(model);
       }
   }

The single viewmodels are defined as 

[Export]
    public class UserMessagesViewModel : Screen
    {
...
}

I've tried using the ActivateItem but in that way I can't set the startup position... how can I do that?
I need to add a menu to the top of the View (that permits the user to select witch operation to do) should I define a model for this? and how can this object tells the dockmanager to position the specific view?
Thanks

Paolo



0
Michele
Top achievements
Rank 2
answered on 28 Nov 2011, 09:46 AM
duplicate post... sorry... I recevied a Server Error message
0
Michele
Top achievements
Rank 2
answered on 01 Dec 2011, 11:34 AM
anyone can help me ?
Thanks
0
Miroslav Nedyalkov
Telerik team
answered on 06 Dec 2011, 10:15 AM
Hello Paolo,

Could you please explain in more details what you need to achieve and how you interact with the Docking control? Is the ActiveItem the ActivePane property of the Docking control? If you could prepare a sample project that demonstrates the idea this would be of great help for us to understand the problem you are experiencing.

Regards,
Miroslav Nedyalkov
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Michele
Top achievements
Rank 2
answered on 06 Dec 2011, 10:20 AM
Hello Miroslav,I've gone a little bit further in these days and I'm able to load an item, so this part is ok... I've got still some iussues about how to organize my models in the sense : I've got 30 view/viewmodels...should my WorkSpaceViewModel contain a reference to each view viewmodel? is there some Activator/Factory that can help me?
0
Michele
Top achievements
Rank 2
answered on 06 Dec 2011, 10:21 AM
Each time I reply to this post I got a server error message... can you please verify?
0
asen
Top achievements
Rank 1
answered on 06 Dec 2011, 10:55 AM
Hi Paolo,

Currently there is a bug related to this thread. We are working on it and it will be fixed in the nearest future. Do not hesitate to post new messages. They will be delivered successfully, however unfortunately you will continue to see the error message screenfor  some more time.
0
Miroslav Nedyalkov
Telerik team
answered on 07 Dec 2011, 09:23 AM
Hello Paolo,

We cannot advice you on this matter as this depends on your project requirements and architecture. I apologize for not being able to assist.

Regards,
Miroslav Nedyalkov
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Noemata
Top achievements
Rank 1
answered on 29 Apr 2014, 05:28 PM
Has anyone done anything more recent, the material here is getting dated.  In addition, none of the information presented here is complete enough to derive a working example.  In particular, the view binding details are not presented for the RadDock control, either for the DockManager implementation or the RadDockingManager implementation mentioned and shown here: https://gist.github.com/dbeattie71/1345512??

It would be very helpful to have more examples showing Telerik integration with Caliburn.Micro given how popular this particular framework is.


0
Vladi
Telerik team
answered on 30 Apr 2014, 08:31 AM
Hello Mario,

Thank you for your feedback about runnable examples of RadDocking integration with the Caliburn Micro  framework.

We will do our best to create such example and include it in our online SDK repository at GitHub. You can find the repository at the following address:https://github.com/telerik/xaml-sdk

Regards,
Vladi
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
Tags
Docking
Asked by
Steve
Top achievements
Rank 1
Answers by
Steve
Top achievements
Rank 1
Marc
Top achievements
Rank 1
Derek
Top achievements
Rank 1
Michele
Top achievements
Rank 2
Chuck
Top achievements
Rank 1
Miroslav Nedyalkov
Telerik team
asen
Top achievements
Rank 1
Noemata
Top achievements
Rank 1
Vladi
Telerik team
Share this question
or