es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo detener un DispatchTimer en el ViewModel cuando se cierra la vista?

Quiero cerrar el temporizador dentro de mi ViewModel cuando la vista se cierre.

Mi código:

MainWindow.xaml.cs:

public MainWindow()
{
    InitializeComponent();
    this.DataContext = new UnitViewModel();

    Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
}

UnitViewModel.cs:

class UnitViewModel : ObservableObject
{
     DispatcherTimer dispatcherTimer = new DispatcherTimer();
     public UnitViewModel()
     {
          StartTimer();
     }

     private void StartTimer()
     {
          dispatcherTimer.Tick += new 
              EventHandler(dispatcherTimer_Tick);
          dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 600);
          dispatcherTimer.Start();
     }

     private void dispatcherTimer_Tick(object sender, EventArgs e)
     {
          UpdateUnit();
     }
}

¿Existe alguna forma de detener este temporizador cuando se cierra la MainWindow? ¿O cuando ya no está abierta? Prefiero tener este código en mi ViewModel, ¿hay alguna manera buena de resolver este problema dentro de MVVM?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Sí, puedes detener el temporizador en tu ViewModel cuando se cierra la vista. Una forma de hacer esto es manejar el evento Closing de la ventana en tu código detrás (MainWindow.xaml.cs) y luego llamar a un método en tu ViewModel para detener el temporizador. Esto viola el patrón MVVM, por lo tanto, en su lugar, puedes usar un comportamiento adjunto para escuchar el evento Window.Closing y ejecutar un comando en tu ViewModel para detener el temporizador.

    Aquí tienes un ejemplo de cómo puedes implementar un comportamiento adjunto:

    WindowClosingBehavior.cs:

    public static class WindowClosingBehavior
    {
        public static readonly DependencyProperty CloseCommandProperty =
            DependencyProperty.RegisterAttached("CloseCommand",
                typeof(ICommand), typeof(WindowClosingBehavior),
                new PropertyMetadata(null, OnCloseCommandChanged));
    
        public static ICommand GetCloseCommand(Window window)
        {
            return (ICommand)window.GetValue(CloseCommandProperty);
        }
    
        public static void SetCloseCommand(Window window, ICommand value)
        {
            window.SetValue(CloseCommandProperty, value);
        }
    
        private static void OnCloseCommandChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window == null)
                return;
            window.Closing -= Window_Closing;
            if (e.NewValue is ICommand command)
            {
                window.Closing += Window_Closing;
            }
        }
    
        private static void Window_Closing(object sender, CancelEventArgs e)
        {
            if (sender is Window window &&
                GetCloseCommand(window) is ICommand command)
            {
                command.Execute(null);
                e.Cancel = true; // cancelar el cierre de la ventana
            }
        }
    }
    

    Este comportamiento escucha el evento Window.Closing y ejecuta un comando cuando la ventana se está cerrando. También cancela el cierre de la ventana estableciendo e.Cancel en true.

    UnitViewModel.cs:

    class UnitViewModel : ObservableObject
    {
        private readonly DispatcherTimer _dispatcherTimer;
    
        public UnitViewModel()
        {
            _dispatcherTimer = new DispatcherTimer();
            StartTimer();
    
            CloseCommand = new DelegateCommand(StopTimer);
        }
    
        public ICommand CloseCommand { get; }
    
        private void StartTimer()
        {
            _dispatcherTimer.Tick += DispatcherTimer_Tick;
            _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 600);
            _dispatcherTimer.Start();
        }
    
        private void DispatcherTimer_Tick(object sender, EventArgs e)
        {
            UpdateUnit();
        }
    
        private void StopTimer()
        {
            _dispatcherTimer.Stop();
        }
    }
    

    En tu ViewModel, creas un CloseCommand que se ejecuta cuando la ventana se está cerrando. El método StopTimer detiene el temporizador.

    MainWindow.xaml:

    <window x:class="MyNamespace.MainWindow" xmlns:behaviors="clr-namespace:MyNamespace.Behaviors" ...="" behaviors:windowclosingbehavior.closecommand="{Binding CloseCommand}">
    

    En tu vista, adjuntas el comportamiento a la ventana y enlazas el CloseCommand a la propiedad CloseCommand del comportamiento.

    Con esta implementación, el temporizador se detendrá cuando la ventana se esté cerrando sin violar el patrón MVVM.

Comments are closed.