6

I use AvalonDock with MVVM in a WPF project.

When I hit the "X" (Close button of the tab) my document closes but stays in memory. It seems that it is only hidden. It is not removed from my Model.Documents collection.

If I add DockingManager_DocumentClosing and try to remove my document from the collection, I receive an Exception in the following method of Xceed.Wpf.AvalonDock.Layout.LayoutContent because parentAsContainer is null.

/// <summary>
/// Close the content
/// </summary>
/// <remarks>Please note that usually the anchorable is only hidden (not closed). By default when user click the X button it only hides the content.</remarks>
public void Close()
{
    var root = Root;
    var parentAsContainer = Parent as ILayoutContainer;
    parentAsContainer.RemoveChild(this);
    if (root != null)
        root.CollectGarbage();
    OnClosed();
}

Does anybody know how I could manage document in AvalonDock that can be removed from my Model.Documents in order to be eventually be disposed when I hit its Close button?

For reference: This is my XAML of the AvalonDock:

<avalonDock:DockingManager
    x:Name="DockingManager" 
    DocumentsSource="{Binding DocumentItems}"  
    ActiveContent="{Binding ActiveMainWindowViewModel,
        Converter={StaticResource RestrictedClassConverter},
        ConverterParameter={x:Type multiSimAnalysis:MainWindowViewModel},
        Mode=TwoWay}"
    DocumentClosing="DockingManager_DocumentClosing"
    ActiveContentChanged="DockingManager_ActiveContentChanged">

  <avalonDock:DockingManager.LayoutItemContainerStyleSelector>
    <pane:PanesStyleSelector>
      <pane:PanesStyleSelector.MainWindowViewLcStyle>
        <Style TargetType="{x:Type avalonDock:LayoutItem}">
          <Setter Property="Title" Value="{Binding Model.Title}"/>
          <Setter Property="ToolTip" Value="{Binding Model.Title}"/>
          <Setter Property="CloseCommand" Value="{Binding Model.CloseCommand}"/>
          <Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
          <Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
          <Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
          <Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
        </Style>
      </pane:PanesStyleSelector.MainWindowViewLcStyle>
    </pane:PanesStyleSelector>
  </avalonDock:DockingManager.LayoutItemContainerStyleSelector>

  <avalonDock:DockingManager.LayoutItemTemplateSelector>
    <multiSimAnalysis:PanesTemplateSelector>
      <multiSimAnalysis:PanesTemplateSelector.MainWindowLcTemplate>
        <DataTemplate>
          <multiSimAnalysis:MainWindowViewLc /> 
        </DataTemplate>
      </multiSimAnalysis:PanesTemplateSelector.MainWindowLcTemplate>
    </multiSimAnalysis:PanesTemplateSelector>
  </avalonDock:DockingManager.LayoutItemTemplateSelector>

  <avalonDock:DockingManager.Theme>
    <avalonDock:VS2010Theme/>
  </avalonDock:DockingManager.Theme>
  <avalonDock:LayoutRoot>
    <avalonDock:LayoutPanel Orientation="Horizontal">
      <avalonDock:LayoutAnchorablePane DockWidth="400">
        <avalonDock:LayoutAnchorable Title="Scope(s) selection" x:Name="PanelScopeSelection" IsVisible="True">
          <scopeSelection:UserControlSelectStudyScope x:Name="ToolScopeSelection"/>
        </avalonDock:LayoutAnchorable>
      </avalonDock:LayoutAnchorablePane>
      <avalonDock:LayoutDocumentPane/>
      <avalonDock:LayoutAnchorablePane DockWidth="150">
        <avalonDock:LayoutAnchorable Title="Properties" x:Name="PanelScopePropertyGrid">
          <!--<multiSimAnalysis:UserControlPropertyGrid x:Name="ToolPropertyGrid"  />-->
          <xctk:PropertyGrid x:Name="ToolPropertyGrid" SelectedObject="{Binding ActiveObject}" />
        </avalonDock:LayoutAnchorable>
      </avalonDock:LayoutAnchorablePane>
    </avalonDock:LayoutPanel>
  </avalonDock:LayoutRoot>
</avalonDock:DockingManager>
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119

3 Answers3

3

I actually find an unacceptable workaround. It is really twisted.

I only give that as reference. There should be a clean way to do it.

    // ************************************************************************
    private void DockingManager_DocumentClosing(object sender, Xceed.Wpf.AvalonDock.DocumentClosingEventArgs e)
    {
        e.Document.CanClose = false;

        DocumentModel documentModel = e.Document.Content as DocumentModel;
        if (documentModel != null)
        {
            Dispatcher.BeginInvoke(new Action(() => this.Model.DocumentItems.Remove(documentModel)), DispatcherPriority.Background);
        }
    }
Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119
  • Is there a way to fix this if you aren't using MVVM? – Bob. Oct 21 '13 at 17:28
  • 1
    This is a long shot, but this event is never called for me, does anyone else have a similar experience? – Mårten Oct 30 '15 at 10:29
  • 1
    @Mårten, I do not use AvalonDock anymore. I use Actipro Docking. – Eric Ouellet Oct 30 '15 at 13:53
  • @EricOuellet where should I write/override this method? – Dan Jan 26 '17 at 11:51
  • @Daniel, there should be an event on the DockingManager named "DocumentClosing" that should occurs before the document close. This is more than 3 years old... perhaps the interface has changed? We are using ActiPro docking actually but you have to pay for. – Eric Ouellet Jan 26 '17 at 13:08
1

I have found that on a LayoutDocument or a LayoutAnchorablePane, applying both this setting works: CanClose="False" or CanFloat="False".

It removes the Close button.

<avalonDock:LayoutDocument Title="Board"
                           ContentId="Board"
                           CanClose="False"
                           CanFloat="False">
</avalonDock:LayoutDocument>
Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
Mallory
  • 11
  • 1
0

Register for IsVisibleChanged.

void layoutFPR_Hidden(object sender, EventArgs e)
{
    LayoutAnchorable window = (LayoutAnchorable)sender;
    YourClass content = window.Content as YourClass;

    // Close the object
    content = null;
    ((LayoutAnchorable)sender).Close();

}