Hi,
I'm using an open-source framework named SoapBox which is for building extensible applications using MEF and WPF with the MVVM. You can get more information about this framework through following links:
Building an Extensible Application with MEF, WPF, and MVVM
SoapBox Core
I get the error in the title when I close view containing DockingManager. But I couldn't reproduce the error without using the SoapBox framework. It must be related with the MEF way of exporting views through ResourceDictionaries using DataTemplates. But I couldn't figure out why and I'm really stuck. I have to use the DockingManager but I can't find a work around. I need an immediate workaround for the problem.
I've tried to minimize the framework and attached a sample which shows the error. When you run the application there will be a tab name 'View with no error" (created in LayoutManagerView.xaml). Select the tab and close it. You won't see the error since it isn't created through MEF. But when you click the menu item View\High Scores on the App tab the same view will be created through MEF (HighScoresView.xaml and HighScoresView.xaml.cs). When you close this view you should get this error:
System.InvalidOperationException: The 'InitialLocation' cannot be changed once a SplitPane is associated with a 'XamDockManager'.
And I figured out that the problem comes from the DockedBottom SplitePane which has a TabGroupPane with three content panes. When you open the solution please add InfragisticsWPF4.v10.3.dll and InfragisticsWPF4.DockManager.v10.3.dll's to lib folder. I've tried to minimize the sample as much as possible but still I used 7z to compress. So when you download the file you need to rename the file as SoapBox_Infragistics.7z
I hope my sample helps someone to figure out the problem.
Thanks in advance
Basically the xamDockManager doesn't allow you to set the InitialLocation after it's been associated with the dockmanager. If you try to change it thereafter it will raise an exception. What seems to be happening is that the changes made by the DataTemplate are being unapplied and as part of that the wpf framework is trying to set the InitialLocation back to the original value. The easiest way around this would be to define your own attached property that conditionally propogates the changes to the SplitPane's InitialLocation. So for example you might add the following to your HighScoresView:
public static InitialPaneLocation? GetInitialLocation(DependencyObject obj){ return (InitialPaneLocation?)obj.GetValue(InitialLocationProperty);} public static void SetInitialLocation(DependencyObject obj, InitialPaneLocation value){ obj.SetValue(InitialLocationProperty, value);} // Using a DependencyProperty as the backing store for InitialPaneLocation. This enables animation, styling, binding, etc...public static readonly DependencyProperty InitialLocationProperty = DependencyProperty.RegisterAttached("InitialLocation", typeof(InitialPaneLocation?), typeof(HighScoresView), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnInitialLocationChanged))); private static void OnInitialLocationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){ // if its getting reset to null because a template is being unapplied then ignore it if (e.NewValue == null) return; SplitPane target = d as SplitPane; Debug.Assert(LogicalTreeHelper.GetParent(target) == null, "The split pane is already associated with an element."); if (LogicalTreeHelper.GetParent(target) != null) return; XamDockManager.SetInitialLocation(target, (InitialPaneLocation)e.NewValue);}
public static InitialPaneLocation? GetInitialLocation(DependencyObject obj){ return (InitialPaneLocation?)obj.GetValue(InitialLocationProperty);}
public static void SetInitialLocation(DependencyObject obj, InitialPaneLocation value){ obj.SetValue(InitialLocationProperty, value);}
// Using a DependencyProperty as the backing store for InitialPaneLocation. This enables animation, styling, binding, etc...public static readonly DependencyProperty InitialLocationProperty = DependencyProperty.RegisterAttached("InitialLocation", typeof(InitialPaneLocation?), typeof(HighScoresView), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnInitialLocationChanged)));
private static void OnInitialLocationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){ // if its getting reset to null because a template is being unapplied then ignore it if (e.NewValue == null) return;
SplitPane target = d as SplitPane;
Debug.Assert(LogicalTreeHelper.GetParent(target) == null, "The split pane is already associated with an element.");
if (LogicalTreeHelper.GetParent(target) != null) return;
XamDockManager.SetInitialLocation(target, (InitialPaneLocation)e.NewValue);}
Then use that property in your xaml instead: <igDock:SplitPane local:HighScoresView.InitialLocation="DockedBottom" Height="330">
I'll try your solution. Thanks for the reply.