如何从viewmodel(Caliburn+WPF)关闭对话框窗口?

19

我有一个ViewModel1和它关联的View1。我使用IWindowManager对象从ViewModel2(另一个视图模型)启动对话框窗口。以下是ViewModel2类中的代码:

windowManager.ShowDialog(new ViewModel());

我有一个包含View1用户控件的对话框窗口。

我的答案是这样的 - 我可以使用红色关闭按钮关闭该对话框窗口,但如何使用我特定的按钮(包含在View1用户控件中)关闭它,例如带有关闭命令的“取消”按钮(Command={Binding CancelCommand}),CancelCommand 当然包含在ViewModel1类中。

3个回答

44

如果你的视图模型扩展了 Caliburn.Micro.Screen,那么这将更加容易实现:

TryClose();

19
只有在尝试关闭主应用程序窗口时,它才会完全关闭整个应用程序。 - Michal T
嗨@MichalT,我正在显示对话框,如await _dialogManager.ShowDialogAsync(item, new List<DialogResult>() { DialogResult.Cancel }); 我想使用计时器关闭它。在tick事件中,当我使用this.DialogHost().TryClose(DialogResult.Cancel);时,this.DialogHost()会返回null。 - Ajendra Prasad

11

你可以通过在ViewModel上实现IViewAware接口来获取当前视图(在你的情况下是对话框窗口)。然后,当你的命令被执行时,可以调用视图(作为对话框创建的Window)的Close方法。

最简单的方法是从ViewAware派生:

public class DialogViewModel : ViewAware
{
    public void ExecuteCancelCommand()
    {
        (GetView() as Window).Close();
    }
}

如果您不被允许派生,您可以自己实现它:

public class DialogViewModel : IViewAware
{
    public void ExecuteCancelCommand()
    {
        dialogWindow.Close();
    }

    private Window dialogWindow;
    public void AttachView(object view, object context = null)
    {
        dialogWindow = view as Window;
        if (ViewAttached != null)
            ViewAttached(this, 
               new ViewAttachedEventArgs(){Context = context, View = view});
    }

    public object GetView(object context = null)
    {
        return dialogWindow;
    }

    public event EventHandler<ViewAttachedEventArgs> ViewAttached;
}

注意:我在示例中使用了Caliburn.Micro 1.3.1。


5
我经常使用的更简洁的方法是使用IResult模式,这样可以抽象出Window实现。 Viewmodel
public IEnumerable<IResult> CloseMe()
{
    yield return new CloseResult();
}

结果代码

public class CloseResult : Result
{
    public override void Execute(ActionExecutionContext context)
    {
        var window = Window.GetWindow(context.View);
        window.Close();            

        base.Execute(context);
    }
}

public abstract class Result : IResult
{
    public virtual void Execute(ActionExecutionContext context)
    {
        OnCompleted(this, new ResultCompletionEventArgs());
    }

    protected virtual void OnCompleted(object sender, ResultCompletionEventArgs e)
    {
        if (Completed != null)
            Completed(sender, e);
    }

    public event EventHandler<ResultCompletionEventArgs> Completed;
}

编辑(仅适用于IoC):如果您想进一步发展,可以为所有屏幕创建一个基类。

public abstract class ShellPresentationModel : Screen
{
    public ShellPresentationModel(IResultFactory resultFactory)
    {
        Result = resultFactory;
    }

    public IResultFactory Result { get; private set; }
}

通过IoC,您可以更轻松地注入依赖项,然后您的VIewmodel关闭方法将如下所示

public IEnumerable<IResult> CloseMe()
{
    yield return Result.Close();
}

一个使用依赖项的IResult示例可以是:
public class ShowDialogResult<TModel> : Result
{
    private readonly IWindowManager windowManager;
    private readonly TModel model;
    private Action<TModel> configure;

    public ShowDialogResult(IWindowManager windowManager, TModel model)
    {
        this.windowManager = windowManager;
        this.model = model;
    }

    public IResult Configure(Action<TModel> configure)
    {
       this.configure = configure;
       return this;
    }

    public override void Execute(ActionExecutionContext context)
    {
        if(configure != null)
            configure(model);

        windowManager.ShowDialog(model);

        base.Execute(context);
    }
}

编辑 刚刚注意到我忘了添加上面IoC示例的一个例子,这里是例子。使用子IoC容器模式,它会像这样。

public IEnumerable<IResult> ShowDialog()
{
    yield return Result.ShowDialog<MyViewModel>();
}

没有子容器模式,您需要手动将父依赖项注入到子容器中。
    yield return Result.ShowDialog<MyViewModel>().Configure(m => m.SomeData = this.SomeData);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接