MVVM way to close document with possibility to cancel out

不羁岁月 提交于 2020-01-14 09:21:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!