[Version 2.0] Handling Tab closure

Mar 5, 2012 at 10:31 AM

Hi Ado,
Any advice on how the ViewModel can be informed of Tab closing?
Currently I can use DockManager.DocumentClosing, but that needs AvalonDock.DocumentClosingEventArgs to get Document.Content, which means the ViewModel needs a refence to AvalonDock

In fact, each of my Tabs is a ViewModel and View (Caliburn Micro's way) so ideally the close button on each tab should inform it's own ViewModel, so a decision as to which is closing is not needed

thanks
John

Mar 5, 2012 at 3:22 PM
Edited Mar 5, 2012 at 3:51 PM

John,

Just removed my previous answer to this.

Have you looked at the example in the latest source code build?

There is a DocumentCloseCommand property on DockingManager that gets fired when a tab is closed.

In the example, this is the command code in the Workspace ViewModel:

        private void OnClose(object parameter)
        {
            var documentToClose = ActiveDocument != null ? ActiveDocument :
                ((LayoutDocument)parameter).Content as FileViewModel;

            if (documentToClose.IsDirty)
            {
                var res = MessageBox.Show(string.Format("Save changes for file '{0}'?", documentToClose.FileName), "AvalonDock Test App", MessageBoxButton.YesNoCancel);
                if (res == MessageBoxResult.Cancel)
                    return;
                if (res == MessageBoxResult.Yes)
                {
                    OnSave(null);
                }
            }

            _files.Remove(documentToClose);
        }

Mar 5, 2012 at 4:29 PM

Hi Steve,
Yes I have and my current example uses it - well I use the event version and the command version.
But to resolve which of the Tabs has caused the controlling viewmodel to be notified needs usage of DocumentClosingEventArgs, which means the controling viewmodel needs a reference to AvalonDock. I was trying to keep such out of the viewmodel.
Even if I bring the LayoutDocumentTabItem's style into the controling viewmodel (ie Conductor One Active) I cannot see how to get the view or viewmodel of the tab that's closing without such a reference.
Its a matter of identifying which of the close buttons in the headers has caused the close.
You can see in the above code example using LayoutDocument as the cast, which is why I suppose Workspace is not called a ViewModel!!
In CM, Workspace is a VM

thanks
John

Mar 5, 2012 at 5:58 PM

Maybe I am not understanding you properly but....

Workspace is a ViewModel - it derives from ViewModelBase and is set as the DataContext for MainWindow.xaml.

In the code example above:

"(LayoutDocument)parameter" is the View object (or tab) being closed.
"((LayoutDocument)parameter).Content" is the ViewModel object being closed.


Steve
Mar 6, 2012 at 10:05 PM
Edited Mar 6, 2012 at 10:06 PM

Steve,
Thank you for your help. I've now solved the Tab Closing problem I had once I understood both AvalonDock and Caliburn.Micro's ActionMessage.
I've created a DocumentHeaderTemplate that contains a close button.
Full solution's code is too much to post here. Here's just the template.

            <avalonDock:DockingManager.DocumentHeaderTemplate>
                <DataTemplate>                 
                    <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Content.DisplayName}"/>
                        <Button x:Name="DocumentCloseButton" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Margin="5,0,0,0" Visibility="Visible" >
                            <Image Source="/AvalonDock;component/Images/PinClose.png"/>                           
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Click">
                                    <cal:ActionMessage MethodName="TabClosing">
                                        <cal:Parameter Value="{Binding Content}" />
                                        <cal:Parameter Value="{Binding IsActive}" />
                                    </cal:ActionMessage>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>                        
                        </Button>
                    </StackPanel>
                </DataTemplate>
            </avalonDock:DockingManager.DocumentHeaderTemplate>

I've updated the Zip on my blog.
I'm pleased with this as Caliburn finds the "Content" as a ViewModel without the need of a reference to AvalonDock in the ViewModel's TabClosing method

thanks
John

Mar 6, 2012 at 11:09 PM

John, 

Caliburn finding the View (content) from the ViewModel is exactly what the DocumentTemplateSelector does already in the DockingManager.

I'll post some source code once I get the Anchorable's working. I already have the Documents working but will hold out for the complete solution.

Steve


Mar 6, 2012 at 11:14 PM

Also, the MVVM example that Ado wrote also has a close button.

Once you fully understand the new AvalonDock, you will probably be able to ditch the Caliburn like I am ditching the DocumentManagerAdapter I borrowed from the thread I linked to.

Once Ado has the Anchorables working with MVVM I'll post an example that shows how to use the DataTemplateSelector in place of Caliburn.

Steve