问题
I'm using Avalondock 2.x for one of my open source projects, if a document is dirty when you close it you should be able to cancel the close.
I am using Caliburn Micro and Coroutine, only way I have been able to solve it is to use C.M to attach to the event
<i:EventTrigger EventName="DocumentClosing">
<cal:ActionMessage MethodName="DocumentClosing">
<cal:Parameter Value="$documentcontext" />
<cal:Parameter Value="$eventArgs" />
</cal:ActionMessage>
</i:EventTrigger>
The event arg has a cancel property. Problem with this approuch is thats its not very MVVM friendly, I have created a little helper method to Coroutinify this like
public IEnumerable<IResult> Coroutinify(IEnumerable<IResult> results, System.Action cancelCallback)
{
return results.Select(r =>
{
if (r is CancelResult)
cancelCallback();
return r;
});
}
Used like
public IEnumerable<IResult> DocumentClosing(ScriptEditorViewModel document, DocumentClosingEventArgs e)
{
return Result.Coroutinify(HandleScriptClosing(document), () => e.Cancel = true);
}
This works but it's a bit clumsy etc, is there a more MVVM way of closing documents in Avalondock with cancel ability?
edit: source code
https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.GUI/Shells/MainShellView.xaml#L29
https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.GUI/Shells/MainShellViewModel.cs#L110
https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.GUI/Result/ResultFactory.cs#L49
回答1:
The way I've accomplished this is by binding to the CloseCommand property of an AvalonDock LayoutItem. When this binding is associated, it overrides the default behavior of closing a document ('X' button, right click close / close all). You then are fully responsible for removing (closing) the document if desired.
The way I set it up was to have a DocumentManagerVM which contains an ObservableCollection of DocumentVMs. Each DocumentVM has an ICommand called RequestCloseCommand, which can close the document by removing itself from the collection of DocumentVMs it's owning DocumentManagerVM.
Specifically, in my DocumentVM viewmodel, there's an ICommand (I'm using mvvmLight RelayCommand) to perform the closing logic:
public RelayCommand RequestCloseCommand { get; private set; }
void RequestClose()
{
// if you want to prevent the document closing, just return from this function
// otherwise, close it by removing it from the collection of DocumentVMs
this.DocumentManagerVM.DocumentVMs.Remove(this);
}
In your view, set up your binding in the LayoutItemContainerStyle or LayoutItemContainerStyleSelector.
<ad:DockingManager
DataContext="{Binding DocumentManagerVM}"
DocumentsSource="{Binding DocumentVMs}">
<ad:DockingManager.LayoutItemContainerStyle>
<Style TargetType="{x:Type ad:LayoutItem}">
<Setter Property="Title" Value="{Binding Model.Header}"/>
<Setter Property="CloseCommand" Value="{Binding Model.RequestCloseCommand}"/>
</Style>
</ad:DockingManager.LayoutItemContainerStyle>
</ad:DockingManager>
来源:https://stackoverflow.com/questions/19268197/mvvm-way-to-close-document-with-possibility-to-cancel-out