The MainWindow of my application is an XamRibbonWindow and its RibbonWindowContentsHost.Content is an XamDockManager. The XamDockManager contains many static and dynamic ContentPane controls within a TabGroupPane. Some of the ContentPane controls get added at run-time and some are added at design time. I would like to save the status of the static (not dynamic) ContentPanes at shutdown such that when the app is restarted where they are docked and if they are pinned is recreated. If I move a ContentPane from being docked on the left to being docked on the right and then shutdown and reopen the application this ContentPane is now displayed on the right side.
So is it possible to configure the PersistenceManager to only save and load the status of specific ContentPanes for where they are docked and if they are pinned?
Thanks,
-eric
OK I tried to create a simple WPF project to try and figure this out. When the RibbonWindow is closing I save the persistence file and on RibbonWindow Initialized I load the persistence file. This is remembering if the ContentPane is Pinned or not Pinned but if I dock it on the right side and close and reopen it does not remember the last docked location and its docked on the left at start up. So far I can only get the IsPinned property to persist correctly. Can anyone offer any advice as to how I can get it to remember the dock location? I have tried to persist the DockManager and the RibbonWindow (which is why these objects are named in the XAML) but when the app loads the DockManager is blank and I can not see the ContentPane. So far persisting the cpMapContents ContentPane is all that seems to work (a little).
I have the following XAML and C# code-behind.
<igRibbon:XamRibbonWindow .... x:Name="ribbonWindow"> <igRibbon:RibbonWindowContentHost> <igRibbon:RibbonWindowContentHost.Ribbon> <igRibbon:XamRibbon x:Name="ribbon" DockPanel.Dock="Top" ApplicationMenuMode="Office2010"> <igRibbon:RibbonTabItem Header="Home"> </igRibbon:RibbonTabItem> </igRibbon:XamRibbon> </igRibbon:RibbonWindowContentHost.Ribbon> <igRibbon:RibbonWindowContentHost.Content> <igDock:XamDockManager x:Name="dockManager"> <igDock:XamDockManager.Panes> <igDock:SplitPanes SplitterOrientation="Horizontal" igDock:XamDockManager.InitialLocation"DockedLeft" Width="300"> <igDock:TabGroupPane> <igDock:ContentPane x:Name="cpMapContents" Header="Map Contents" AllowInDocumentHost="False" IsPnned="True" SerializationId="cpMapContents" /> </igDock:TabGroupPane> </igDock:SplitPanes> </igDock:XamDockManager.Panes> </igDock:XamDockManager> </igRibbon:RibbonWindowContentHost.Content> </igRibbon:RibbonWindowContentHost></igRibbon:XamRibbonWindow>----------------------------public partial class MainWindow : XamRibbonWindow { public MainWindow(){ InitializeComponent(); } private const string _fileName = @"C:\temp\data.txt"; private void XamRibbonWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { using (MemoryStream memoryStream = PersistenceManager.Save(cpMapContents)) { using (FileStream fileStream = new FileStream(_fileName, FileMode.Create, FileAccess.Write)) { memoryStream.WriteTo(fileStream); } } } private void XamRibbonWindow_Initialized(object sender, EventArgs e) { If (File.Exists(_fileName)) { using (FileStream fileStream = new FileStream(_fileName, FileMode.Open)) { PersistenceManager.Load(cpMapContents, fileStream); } } }}
Hello Eric,
Thank you for your post. I have been looking into it and I can suggest you use the built in functionality for save/load layouts of the XamDockManager, by using its SaveLayout and LoadLayout methods. You can see how to use them in the Samples Browser under xamDockManager / Display / Loading and Saving Layouts section. Please let me know if this helps you or you need further assistance on this matter.
Looking forward for your reply.
Yes I did find other samples that show what you suggested. This is what I ended up with in the code behind of the main window.
public partial class MainWindow : XamRibbonWindow { private const string _layoutPath = @"C:\temp\layout.xml"; private void XamRibbon_Closing(object sender, CancelEventArgs e) { using (System.IO.Stream stream = new System.IO.FileStream(_layoutPath, FileMode.Create)) { this.dockManager.SaveLayout(stream); } } protected override void OnSourceInitialized (EventArgs e){ if (System.IO.File.Exists(_layoutPath)) { using (System.IO.Stream stream = new System.IO.FileStream(_layoutPath, FileMode.Open)) { this.dockManager.LoadLayout(stream); } } }}
In the XAML I used the SaveInLayout property for any ContentPanels I wanted to persist their state.
This is working well but I now have another issue. I can start a new thread if you like for this new issue. In my Ribbon I have a button that opens the ContentPanel if its not already open. Most of my ContentPanels are not visible by default. The first time panel is displayed the Content of the panel is set. Most of our panels need to call out to a web service to get the data to be displayed (i.e. in a list). In the code behind this is how we are performing this.
private void btnBookmarks_Click(object sender, RoutedEventArgs e) { if (cpBookmarks.Content == null) { cpBookmarks.Content = App.GetResource(typeof(BookmarksView)); } cpBookmarks.Visibility = System.Windows.Visiblity.Visible; cpBookmarks.Activate();}
On the Ribbon I have a Button called btnBookmarks with its click event set to btnBookmarks_Click. There is also a ContentPanel in the XAML named cpBookmarks.
<igDock:ContentPane x:Name="cpBookmarks" Header="Bookmarks" AllowInDocumentHost="False" Visiblity="Collapsed" .... />
Notice that the Content of the ContentPane is not defined in the XMAL and its Collapsed by default. If we set the content in the XAML then when the application is loading it creates all the content for all the ContentPanes and it slows down the startup time. This approach was used so that the Content and data was created on demand the first time.
Now the problem is if we persist the fact that the cpBookmarks is open its content is empty because it was not opened by the button click but by the layout persistence information. For now we have made the following changes to deal with this issue.
private void btnBookmarks_Click(object sender, RoutedEventArgs e) { cpBookmarks.Visibility = System.Windows.Visiblity.Visible; cpBookmarks.Activate();}private void cpMapContents_Initialized(object sender, EventArgs e) { if (cpBookmarks.Content == null) { cpBookmarks.Content = App.GetResource(typeof(BookmarksView)); }}
Basically all we do on the button click is make the ContentPane visible and Activate it. This will cause the Initialized event to be raised by the ContentPane. This is where we can check if its Content is null and set it. When the layout persistence information opens this ContentPanel at start up it will also raise the same Initialized event and the content gets generated.
While this works this seems a bit cumbersome and would require more code in the code-behind. We are trying to follow an MVVM pattern as best we can and we were wondering if there was some other way to deal with setting content on demand from a button click to open the ContentPane and from opening the ContentPane from persisted layout information.
I am glad that you were able to resolve your issue about the save/ load of the ContentPanes. As for the loading ion deamnd question, I believe that the approach you are using is the best one for achieving the functionality you want. If I think of a better one I will let you know.