visual ventana programar formulario deshabilitar cerrar boton aplicacion anterior abrir c# wpf mvvm

ventana - deshabilitar boton cerrar formulario c#



¿Cómo debe el ViewModel cerrar el formulario? (26)

¿Por qué no simplemente pasar la ventana como un parámetro de comando?

DO#:

private void Cancel( Window window ) { window.Close(); } private ICommand _cancelCommand; public ICommand CancelCommand { get { return _cancelCommand ?? ( _cancelCommand = new Command.RelayCommand<Window>( ( window ) => Cancel( window ), ( window ) => ( true ) ) ); } }

XAML:

<Window x:Class="WPFRunApp.MainWindow" x:Name="_runWindow" ... <Button Content="Cancel" Command="{Binding Path=CancelCommand}" CommandParameter="{Binding ElementName=_runWindow}" />

Estoy tratando de aprender WPF y el problema MVVM, pero he encontrado un obstáculo. Esta pregunta es similar pero no es lo mismo que esta (manejo-diálogos en wpf-con-mvvm) ...

Tengo un formulario de "Inicio de sesión" escrito usando el patrón MVVM.

Este formulario tiene un ViewModel que contiene el nombre de usuario y la contraseña, que están vinculados a la vista en el XAML utilizando enlaces de datos normales. También tiene un comando de "Inicio de sesión" que está vinculado al botón "Iniciar sesión" en el formulario, utilizando un enlace de datos normal.

Cuando se activa el comando "Iniciar sesión", invoca una función en el ViewModel que se activa y envía datos a través de la red para iniciar sesión. Cuando esta función finaliza, hay 2 acciones:

  1. El inicio de sesión no fue válido: solo mostramos un MessageBox y todo está bien

  2. El inicio de sesión fue válido, debemos cerrar el formulario de inicio de sesión y devolverlo como verdadero a su DialogResult ...

El problema es que ViewModel no sabe nada acerca de la vista real, entonces, ¿cómo puede cerrar la vista y decirle que devuelva un DialogResult particular? Podría pegar algo de código en el CodeBehind y / o pasar la vista a ViewModel, pero parece que eso anularía todo el punto de MVVM ...

Actualizar

Al final, acabo de violar la "pureza" del patrón de MVVM e hice que View publicara un evento Closed y expusiera un método Close . El ViewModel solo llamaría a view.Close . La vista solo se conoce a través de una interfaz y se cablea a través de un contenedor IOC, por lo que no se pierde la capacidad de prueba ni la capacidad de mantenimiento.

¡Parece bastante tonto que la respuesta aceptada sea de -5 votos! Si bien soy consciente de los buenos sentimientos que uno obtiene al resolver un problema mientras es "puro", seguramente no soy el único que piensa que 200 líneas de eventos, comandos y comportamientos solo para evitar un método de una línea en el nombre de "patrones" y "pureza" es un poco ridículo ...


Desde mi punto de vista, la pregunta es bastante buena, ya que el mismo enfoque se usaría no solo para la ventana "Iniciar sesión", sino para cualquier tipo de ventana. He revisado muchas sugerencias y ninguna está bien para mí. Por favor revise mi sugerencia que fue tomada del artículo del patrón de diseño de MVVM .

Cada clase de ViewModel debe heredar de WorkspaceViewModel que tiene el evento RequestClose y la propiedad CloseCommand del tipo ICommand . La implementación predeterminada de la propiedad CloseCommand generará el evento RequestClose .

Para cerrar la ventana, el método OnLoaded de su ventana debe ser anulado:

void CustomerWindow_Loaded(object sender, RoutedEventArgs e) { CustomerViewModel customer = CustomerViewModel.GetYourCustomer(); DataContext = customer; customer.RequestClose += () => { Close(); }; }

o el método OnStartup de su aplicación:

protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); MainWindow window = new MainWindow(); var viewModel = new MainWindowViewModel(); viewModel.RequestClose += window.Close; window.DataContext = viewModel; window.Show(); }

Supongo que la implementación del evento RequestClose y la propiedad CloseCommand en WorkspaceViewModel son bastante claras, pero les mostraré que sean coherentes:

public abstract class WorkspaceViewModel : ViewModelBase // There''s nothing interesting in ViewModelBase as it only implements the INotifyPropertyChanged interface { RelayCommand _closeCommand; public ICommand CloseCommand { get { if (_closeCommand == null) { _closeCommand = new RelayCommand( param => Close(), param => CanClose() ); } return _closeCommand; } } public event Action RequestClose; public virtual void Close() { if ( RequestClose != null ) { RequestClose(); } } public virtual bool CanClose() { return true; } }

Y el código fuente de RelayCommand :

public class RelayCommand : ICommand { #region Constructors public RelayCommand(Action<object> execute, Predicate<object> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } #endregion // Constructors #region ICommand Members [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { _execute(parameter); } #endregion // ICommand Members #region Fields readonly Action<object> _execute; readonly Predicate<object> _canExecute; #endregion // Fields }

PD: ¡No me trates mal por esas fuentes! Si los tuviera ayer, me hubieran ahorrado unas horas ...

PPS Cualquier comentario o sugerencia son bienvenidos.


Esta es una solución simple y limpia: agrega un evento a ViewModel e indica a la Ventana que se cierre por sí sola cuando se dispare ese evento.

Para más detalles, vea mi entrada de blog, Cerrar ventana desde ViewModel .


Esto es lo que hice inicialmente, que funciona, sin embargo, parece bastante largo y feo (la estática global nada es bueno)

1: App.xaml.cs

public partial class App : Application { // create a new global custom WPF Command public static readonly RoutedUICommand LoggedIn = new RoutedUICommand(); }

2: LoginForm.xaml

// bind the global command to a local eventhandler <CommandBinding Command="client:App.LoggedIn" Executed="OnLoggedIn" />

3: LoginForm.xaml.cs

// implement the local eventhandler in codebehind private void OnLoggedIn( object sender, ExecutedRoutedEventArgs e ) { DialogResult = true; Close(); }

4: LoginFormViewModel.cs

// fire the global command from the viewmodel private void OnRemoteServerReturnedSuccess() { App.LoggedIn.Execute(this, null); }

Más tarde, luego LoginFormViewModel todo este código, y acabo de hacer que LoginFormViewModel llame al método Close en su vista. Terminó siendo mucho más agradable y fácil de seguir. En mi opinión, el objetivo de los patrones es brindar a las personas una manera más fácil de entender lo que está haciendo su aplicación, y en este caso, MVVM hacía que esto fuera mucho más difícil de entender que si no lo hubiera usado, y ahora era un anti- patrón.


Hay muchos comentarios que argumentan los pros y los contras de MVVM aquí. Para mí, estoy de acuerdo con Nir; Se trata de usar el patrón de forma adecuada y MVVM no siempre encaja. La gente parece estar dispuesta a sacrificar todos los principios más importantes del diseño de software SOLO para que se ajuste a MVVM.

Dicho esto, ... creo que tu caso podría encajar bien con un poco de refactorización.

En la mayoría de los casos que he encontrado, WPF le permite sobrevivir SIN varias Window . Tal vez podría intentar usar Frame s y Page s en lugar de Windows con DialogResult s.

En su caso, mi sugerencia sería que LoginFormViewModel maneje LoginCommand y, si el inicio de sesión no es válido, establezca una propiedad en LoginFormViewModel en un valor apropiado ( false o algún valor de enumeración como UserAuthenticationStates.FailedAuthentication ). Haría lo mismo para un inicio de sesión exitoso ( true o algún otro valor de enumeración). Luego usaría un DataTrigger que responde a los diversos estados de autenticación del usuario y podría usar un Setter simple para cambiar la propiedad Source del Frame .

Tener su ventana de inicio de sesión devolver un DialogResult creo que es donde se está confundiendo; ese DialogResult es realmente una propiedad de su ViewModel. En mi experiencia, ciertamente limitada, con WPF, cuando algo no se siente bien por lo general porque pienso en términos de cómo habría hecho lo mismo en WinForms.

Espero que ayude.


He leído todas las respuestas, pero debo decir que la mayoría de ellas no son lo suficientemente buenas o incluso peores.

Podría manejar esto de manera hermosa con la clase DialogService , cuya responsabilidad es mostrar la ventana de diálogo y devolver el resultado del diálogo. He creado un proyecto de muestra que demuestra su implementación y uso.

Aquí están las partes más importantes:

//we will call this interface in our viewmodels public interface IDialogService { bool? ShowDialog(object dialogViewModel, string caption); } //we need to display logindialog from mainwindow public class MainWindowViewModel : ViewModelBase { public string Message {get; set;} public void ShowLoginCommandExecute() { var loginViewModel = new LoginViewModel(); var dialogResult = this.DialogService.ShowDialog(loginViewModel, "Please, log in"); //after dialog is closed, do someting if (dialogResult == true && loginViewModel.IsLoginSuccessful) { this.Message = string.Format("Hello, {0}!", loginViewModel.Username); } } } public class DialogService : IDialogService { public bool? ShowDialog(object dialogViewModel, string caption) { var contentView = ViewLocator.GetView(dialogViewModel); var dlg = new DialogWindow { Title = caption }; dlg.PART_ContentControl.Content = contentView; return dlg.ShowDialog(); } }

¿No es esto más simple? ¿más estricto, más legible y por último, pero no menos fácil de depurar que EventAggregator u otras soluciones similares?

Como puede ver, en mi opinión, los modelos que he utilizado el primer enfoque de ViewModel se describen en mi publicación aquí: Prácticas recomendadas para llamar a View from ViewModel en WPF

Por supuesto, en el mundo real, el DialogService.ShowDialog debe tener más opciones para configurar el diálogo, por ejemplo, los botones y comandos que deben ejecutar. Hay diferentes maneras de hacerlo, pero está fuera de alcance :)


Implementé la solución de Joe White, pero tuve problemas con errores ocasionales " DialogResult solo se puede configurar después de crear y mostrar Windows como diálogo ".

Mantuve el ViewModel cuando se cerró la Vista y ocasionalmente abrí una nueva Vista con la misma VM. Parece que cerrar la nueva Vista antes de que se haya recolectado la vista anterior dio como resultado que DialogResultChanged intentara establecer la propiedad DialogResult en la ventana cerrada, provocando el error.

Mi solución fue cambiar DialogResultChanged para verificar la propiedad IsLoaded de la ventana:

private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window != null && window.IsLoaded) window.DialogResult = e.NewValue as bool?; }

Después de hacer este cambio, se ignoran todos los archivos adjuntos a los cuadros de diálogo cerrados.


La forma en que lo manejaría es agregar un controlador de eventos en mi ViewModel. Cuando el usuario haya iniciado sesión correctamente, dispararía el evento. En mi Vista me adjuntaría a este evento y cuando se activara cerraría la ventana.


Me inspiré en la respuesta de Thejuan para escribir una propiedad adjunta más simple. Sin estilos, sin disparadores; en su lugar, puedes hacer esto:

<Window ... xmlns:xc="clr-namespace:ExCastle.Wpf" xc:DialogCloser.DialogResult="{Binding DialogResult}">

Esto es casi tan limpio como si el equipo de WPF lo hubiera hecho bien y hubiera hecho de DialogResult una propiedad de dependencia en primer lugar. Solo pones un bool? DialogResult bool? DialogResult propiedad bool? DialogResult en su ViewModel e implementa INotifyPropertyChanged, y voilà, su ViewModel puede cerrar la ventana (y configurar su DialogResult) simplemente configurando una propiedad. MVVM como debe ser.

Aquí está el código para DialogCloser:

using System.Windows; namespace ExCastle.Wpf { public static class DialogCloser { public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached( "DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window != null) window.DialogResult = e.NewValue as bool?; } public static void SetDialogResult(Window target, bool? value) { target.SetValue(DialogResultProperty, value); } } }

También he publicado esto en mi blog .


Otra solución es crear una propiedad con INotifyPropertyChanged en View Model como DialogResult, y luego en Code Behind escriba esto:

public class SomeWindow: ChildWindow { private SomeViewModel _someViewModel; public SomeWindow() { InitializeComponent(); this.Loaded += SomeWindow_Loaded; this.Closed += SomeWindow_Closed; } void SomeWindow_Loaded(object sender, RoutedEventArgs e) { _someViewModel = this.DataContext as SomeViewModel; _someViewModel.PropertyChanged += _someViewModel_PropertyChanged; } void SomeWindow_Closed(object sender, System.EventArgs e) { _someViewModel.PropertyChanged -= _someViewModel_PropertyChanged; this.Loaded -= SomeWindow_Loaded; this.Closed -= SomeWindow_Closed; } void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == SomeViewModel.DialogResultPropertyName) { this.DialogResult = _someViewModel.DialogResult; } } }

El fragmento más importante es _someViewModel_PropertyChanged . DialogResultPropertyName puede ser una cadena de const de pública en SomeViewModel .

Utilizo este tipo de truco para hacer algunos cambios en los controles de vista en caso de que sea difícil hacerlo en ViewModel. OnPropertyChanged en ViewModel puede hacer lo que quiera en View. ViewModel sigue siendo ''comprobable por unidad'' y algunas pequeñas líneas de código en el código detrás no hacen ninguna diferencia.


Para su información, me encontré con el mismo problema y creo que resolví una solución que no requiere globales o estadísticas, aunque puede que no sea la mejor respuesta. Dejo que ustedes decidan eso por ustedes mismos.

En mi caso, el ViewModel que crea una instancia de la ventana que se mostrará (llamémosla ViewModelMain) también conoce el LoginFormViewModel (usando la situación anterior como ejemplo).

Entonces, lo que hice fue crear una propiedad en LoginFormViewModel que era de tipo ICommand (Llamémosla CloseWindowCommand). Luego, antes de llamar a .ShowDialog () en la ventana, establezco la propiedad CloseWindowCommand en el LoginFormViewModel en el método window.Close () de la ventana que he creado. Luego, dentro de LoginFormViewModel, todo lo que tengo que hacer es llamar a CloseWindowCommand.Execute () para cerrar la ventana.

Es un poco de una solución alternativa / hackeo, supongo, pero funciona bien sin romper realmente el patrón MVVM.

Siéntase libre de criticar este proceso todo lo que quiera, ¡lo puedo tomar! :)


Podría hacer que ViewModel exponga un evento en el que se registra View. Luego, cuando el ViewModel decide su hora de cerrar la vista, dispara ese evento que hace que la vista se cierre. Si desea que un valor de resultado específico sea devuelto, entonces tendría una propiedad en ViewModel para eso.


Probablemente sea muy tarde, pero encontré el mismo problema y encontré una solución que me funciona.

No puedo imaginar cómo crear una aplicación sin diálogos (tal vez sea solo un bloqueo mental). Así que estaba en un callejón sin salida con MVVM y mostrando un diálogo. Así que me encontré con este artículo de CodeProject:

http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

Que es un UserControl que básicamente permite que una ventana esté dentro del árbol visual de otra ventana (no permitido en xaml). También expone una propiedad de dependencia booleana llamada IsShowing.

Puede establecer un estilo como, normalmente en un diccionario de recursos, que básicamente muestra el cuadro de diálogo cuando la propiedad Content del control! = Null mediante disparadores:

<Style TargetType="{x:Type d:Dialog}"> <Style.Triggers> <Trigger Property="HasContent" Value="True"> <Setter Property="Showing" Value="True" /> </Trigger> </Style.Triggers> </Style>

En la vista en la que desea visualizar el diálogo, simplemente tenga esto:

<d:Dialog Content="{Binding Path=DialogViewModel}"/>

Y en su ViewModel, todo lo que tiene que hacer es establecer la propiedad en un valor (Nota: la clase ViewModel debe admitir INotifyPropertyChanged para que la vista sepa que sucedió algo).

al igual que:

DialogViewModel = new DisplayViewModel();

Para hacer coincidir el ViewModel con la vista, debe tener algo como esto en un diccionario de recursos:

<DataTemplate DataType="{x:Type vm:DisplayViewModel}"> <vw:DisplayView/> </DataTemplate>

Con todo eso obtienes un código de una sola línea para mostrar el diálogo. El problema que obtienes es que realmente no puedes cerrar el diálogo solo con el código anterior. Por eso es que tiene que poner un evento en una clase base de ViewModel del cual DisplayViewModel hereda y en lugar del código anterior, escriba esto

var vm = new DisplayViewModel(); vm.RequestClose += new RequestCloseHandler(DisplayViewModel_RequestClose); DialogViewModel = vm;

A continuación, puede manejar el resultado del diálogo a través de la devolución de llamada.

Esto puede parecer un poco complejo, pero una vez que se sientan las bases, es bastante sencillo. Una vez más, esta es mi implementación, estoy seguro de que hay otros :)

Espero que esto ayude, me salvó.


Si bien esto no responde a la pregunta de cómo hacer esto a través del modelo de vista, muestra cómo hacerlo usando solo XAML + el SDK combinado.

Elegí descargar y usar dos archivos del SDK de Blend, que puedes usar como paquete de Microsoft a través de NuGet. Los archivos son:

System.Windows.Interactivity.dll y Microsoft.Expression.Interactions.dll

Microsoft.Expression.Interactions.dll le brinda buenas capacidades, como la capacidad de establecer propiedades o invocar un método en su viewmodel u otro objetivo y también tiene otros widgets en su interior.

Algunos XAML:

<Window x:Class="Blah.Blah.MyWindow" ... xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" ...> <StackPanel> <Button x:Name="OKButton" Content="OK"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <ei:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PropertyName="DialogResult" Value="True" IsEnabled="{Binding SomeBoolOnTheVM}" /> </i:EventTrigger> </Button> <Button x:Name="CancelButton" Content="Cancel"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <ei:ChangePropertyAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PropertyName="DialogResult" Value="False" /> </i:EventTrigger> </Button> <Button x:Name="CloseButton" Content="Close"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <!-- method being invoked should be void w/ no args --> <ei:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" MethodName="Close" /> </i:EventTrigger> </i:Interaction.Triggers> </Button> <StackPanel> </Window>

Tenga en cuenta que si simplemente va por el simple comportamiento de Aceptar / Cancelar, puede alejarse usando las propiedades IsDefault e IsCancel siempre que la ventana se muestre con Window.ShowDialog ().
Personalmente tuve problemas con un botón que tenía la propiedad IsDefault establecida en verdadero, pero estaba oculta cuando se carga la página. Parece que no quería jugar bien después de que se mostró, así que simplemente estoy configurando la propiedad Window.DialogResult como se muestra arriba y funciona para mí.


Solo para agregar al número masivo de respuestas, quiero agregar lo siguiente. Suponiendo que tenga un ICommand en su ViewModel, y desea que ese comando cierre su ventana (o cualquier otra acción), puede usar algo como lo siguiente.

var windows = Application.Current.Windows; for (var i=0;i< windows.Count;i++ ) if (windows[i].DataContext == this) windows[i].Close();

No es perfecto, y puede ser difícil de probar (ya que es difícil simular / apagar una estática) pero es más limpio (IMHO) que las otras soluciones.

Erick


Suponiendo que su diálogo de inicio de sesión es la primera ventana que se crea, intente esto dentro de su clase LoginViewModel:

void OnLoginResponse(bool loginSucceded) { if (loginSucceded) { Window1 window = new Window1() { DataContext = new MainWindowViewModel() }; window.Show(); App.Current.MainWindow.Close(); App.Current.MainWindow = window; } else { LoginError = true; } }


Terminé mezclando la respuesta de Joe White y un poco de código de la respuesta de Adam Mills , ya que necesitaba mostrar un control de usuario en una ventana creada mediante programación. Así que el DialogCloser no necesita estar en la ventana, puede estar en el propio control del usuario

<UserControl ... xmlns:xw="clr-namespace:Wpf" xw:DialogCloser.DialogResult="{Binding DialogResult}">

Y el DialogCloser encontrará la ventana del control del usuario si no se adjuntó a la misma ventana.

namespace Wpf { public static class DialogCloser { public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached( "DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d.GetWindow(); if (window != null) window.DialogResult = e.NewValue as bool?; } public static void SetDialogResult(DependencyObject target, bool? value) { target.SetValue(DialogResultProperty, value); } } public static class Extensions { public static Window GetWindow(this DependencyObject sender_) { Window window = sender_ as Window; return window ?? Window.GetWindow( sender_ ); } } }



Yo iría por aquí

using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Messaging; // View public partial class TestCloseWindow : Window { public TestCloseWindow() { InitializeComponent(); Messenger.Default.Register<CloseWindowMsg>(this, (msg) => Close()); } } // View Model public class MainViewModel: ViewModelBase { ICommand _closeChildWindowCommand; public ICommand CloseChildWindowCommand { get { return _closeChildWindowCommand?? (_closeChildWindowCommand = new RelayCommand(() => { Messenger.Default.Send(new CloseWindowMsg()); })); } } } public class CloseWindowMsg { }


Ok, entonces esta pregunta tiene casi 6 años y todavía no puedo encontrar lo que creo que es la respuesta correcta, así que permítame compartir mis "2 centavos" ...

De hecho, tengo 2 formas de hacerlo, la primera es la simple ... la segunda es la correcta, así que si buscas la correcta, solo salta # 1 y salta a la # 2 :

1. Rápido y fácil (pero no completo)

Si solo tengo un pequeño proyecto, a veces solo creo una CloseWindowAction en el ViewModel:

public Action CloseWindow { get; set; } // In MyViewModel.cs

Y quien sea que cree la Vista, o en el código de la Vista que está detrás, simplemente establezco el Método que llamará la Acción:

(recuerde que MVVM se refiere a la separación de la Vista y el Modelo de Vista ... el código de la Vista se ve como la Vista y siempre que haya una separación adecuada, no está violando el patrón)

Si algún ViewModel crea una nueva ventana:

private void CreateNewView() { MyView window = new MyView(); window.DataContext = new MyViewModel { CloseWindow = window.Close, }; window.ShowDialog(); }

O si lo desea en su ventana principal, simplemente colóquelo debajo del constructor de su Vista:

public MyView() { InitializeComponent(); this.DataContext = new MainViewModel { CloseWindow = this.Close }; }

cuando desee cerrar la ventana, simplemente llame a la Acción en su ViewModel.

2. El camino correcto

Ahora la forma correcta de hacerlo es utilizando Prism (IMHO), y todo lo que se puede encontrar aquí .

Puede realizar una solicitud de interacción , rellenarla con los datos que necesitará en su nueva ventana, almorzarla, cerrarla e incluso recibir los datos . Todo esto encapsulado y aprobado por MVVM. Incluso obtiene un estado de cómo se cerró la ventana , por ejemplo, si el usuario Canceled o Accepted (botón OK) la ventana y los datos si los necesita . Es un poco más complicado y la respuesta n. ° 1, pero es mucho más completa y un patrón recomendado por Microsoft.

El enlace que proporcioné contiene todos los fragmentos de código y ejemplos, por lo que no me molestaré en colocar ningún código aquí, solo lea el artículo de descarga de Prism Quick Start y ejecútelo. Es muy sencillo de entender, solo un poco más detallado. Haz que funcione, pero los beneficios son mayores que simplemente cerrar una ventana.


Aquí está la solución simple libre de errores (con código fuente), está funcionando para mí.

  1. Derive su ViewModel de INotifyPropertyChanged

  2. Crear una propiedad observable CerrarDialog en ViewModel

    public void Execute() { // Do your task here // if task successful, assign true to CloseDialog CloseDialog = true; } private bool _closeDialog; public bool CloseDialog { get { return _closeDialog; } set { _closeDialog = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName]string property = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } }

    }

  3. Adjunte un controlador a la vista para este cambio de propiedad

    _loginDialogViewModel = new LoginDialogViewModel(); loginPanel.DataContext = _loginDialogViewModel; _loginDialogViewModel.PropertyChanged += OnPropertyChanged;

  4. Ahora que casi has terminado. En el evento del controlador make.DialogResult = true

    protected void OnPropertyChanged(object sender, PropertyChangedEventArgs args) { if (args.PropertyName == "CloseDialog") { DialogResult = true; } }


Cuando necesite cerrar la ventana, simplemente coloque esto en el modelo de visualización:

ta-da

foreach (Window window in Application.Current.Windows) { if (window.DataContext == this) { window.Close(); return; } }


El comportamiento es la forma más conveniente aquí.

  • Por un lado, se puede vincular al modelo de vista dado (que puede indicar "cerrar el formulario!")

  • Por otra parte, tiene acceso al formulario en sí mismo, por lo que puede suscribirse a los eventos específicos necesarios para el formulario, mostrar un cuadro de diálogo de confirmación o cualquier otra cosa.

Escribir el comportamiento necesario se puede ver aburrido por primera vez. Sin embargo, de ahora en adelante, puede reutilizarlo en cada formulario que necesite por fragmento de código XAML exacto. Y si es necesario, puede extraerlo como un conjunto separado para que pueda incluirse en el próximo proyecto que desee.


Crea una Dependency Propertyen tu View/ cualquier UserControl(o Windowquieres cerrar). Como abajo:

public bool CloseTrigger { get { return (bool)GetValue(CloseTriggerProperty); } set { SetValue(CloseTriggerProperty, value); } } public static readonly DependencyProperty CloseTriggerProperty = DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(ControlEventBase), new PropertyMetadata(new PropertyChangedCallback(OnCloseTriggerChanged))); private static void OnCloseTriggerChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) { //write Window Exit Code }

Y enlácelo desde la propiedad de su ViewModel :

<Window x:Class="WpfTempProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="525" CloseTrigger="{Binding Path=CloseWindow,Mode=TwoWay}"

Propiedad en VeiwModel:

private bool closeWindow; public bool CloseWindow { get { return closeWindow; } set { closeWindow = value; RaiseChane("CloseWindow"); } }

Ahora active la operación de cierre cambiando el CloseWindowvalor en ViewModel. :)


Application.Current.MainWindow.Close()

¡Eso es suficiente!


public partial class MyWindow: Window { public ApplicationSelection() { InitializeComponent(); MyViewModel viewModel = new MyViewModel(); DataContext = viewModel; viewModel.RequestClose += () => { Close(); }; } } public class MyViewModel { //...Your code... public event Action RequestClose; public virtual void Close() { if (RequestClose != null) { RequestClose(); } } public void SomeFunction() { //...Do something... Close(); } }