2012-04-10 21 views
19

Tengo ViewModel1 y View1 asociado a él. Empiezo la ventana de diálogo desde ViewModel2 (algunos otros modelos de vista) usando el objeto IWindowManager. El código de ViewModel2 clase:¿Cómo cerrar la ventana de diálogo desde el modelo de vista (Caliburn + WPF)?

windowManager.ShowDialog(new ViewModel()); 

lo tanto, tengo la ventana de diálogo con un control de usuario View1.

Mi respuesta es siguiente: puedo cerrar esa ventana de diálogo usando el botón rojo cerrar, pero cómo cerrarlo usando mi botón específico (contenido en View1 control de usuario), algo así como "Cancelar" con el comando cerrar (Command={Binding CancelCommand}), CancelCommand por supuesto está contenido en la clase ViewModel1.

Respuesta

36

Es aún más fácil si el modelo de vista se extiende Caliburn.Micro.Screen:

TryClose(); 
+0

TryClose intenta cerrar toda la aplicación ... – Tim

+16

Bueno, cierra la aplicación completa solo si está intentando cerrar la ventana principal de la aplicación. –

+0

que acaba de salvar mi día :-) – juFo

10

Puede obtener la vista actual (en su caso, la ventana de diálogo) con la implementación de la interfaz IViewAware en su ViewModel. Luego puede llamar al Close en la vista (el Window creado como el cuadro de diálogo) cuando se ejecuta su comando.

La forma más fácil es por eso que se derivan de ViewAware:

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

Si no se le permite deducir que puede implementarlo:

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; 
} 

Nota: He usado Caliburn.Micro 1.3 .1 para mi muestra.

+0

Eso es todo! ¡Muchas gracias!)))) –

5

una forma más limpia (Asunto de gusto personal) que utilizo mucho es utilizar el patrón de iResult, de esta manera abstracta el implemenation Ventana

viewmodel

public IEnumerable<IResult> CloseMe() 
{ 
    yield return new CloseResult(); 
} 

Código de resultado

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; 
} 

editar (Solo es necesario para IoC): Si quieres dar un paso más, haces una clase base para todas las pantallas

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

    public IResultFactory Result { get; private set; } 
} 

esta manera se puede inyectar dependencias con una COI mucho más fácil, entonces su modelo de vista estrecha método se verá así

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

Un ejemplo de un iResult que utiliza la dependencia puede ser

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); 
    } 
} 

edit Acabo de darme cuenta de que olvidé agregar un ejemplo del exmaple IoC anterior, aquí va Con un IoC para niños que contiene patrón er que se vería así

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

Sin un patrón contenedor secundario que tendría que inyectar dependeync padres en el niño manualmente

yield return Result.ShowDialog<MyViewModel>().Configure(m => m.SomeData = this.SomeData); 
Cuestiones relacionadas