Остановить экземпляр DispatcherTimer или изменить его значение

Мое приложение работает следующим образом: я выбираю момент времени в прошлом, выбираю количество времени с этого момента («В течение 3 часов...») и нажимаю «Добавить таймер». Это создает новую панель стека, которая включает в себя таймер, который отсчитывает, сколько времени осталось ровно до x часов с этого момента времени.

В 20, 15 и 10 минут до конца воспроизводится звуковой сигнал.

Теперь моя проблема заключается в том, что если я нажму «Удалить» рядом с сгенерированным таймером (который удалит вместе с ним всю панель стека), обратный отсчет все еще будет работать в фоновом режиме, и когда он достигнет 20/15/10 минут, он все еще издает звуки.

Мне пришлось бы либо сбросить эти удаленные таймеры на 0, либо остановить их, либо... Я не уверен, как это сделать. Вероятно, мне следовало использовать привязку данных, но я не уверен, что понимаю ее достаточно, чтобы реализовать ее здесь. Кто-нибудь может помочь?

<Window x:Class="Alertimer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        xmlns:local="clr-namespace:Alertimer"
        mc:Ignorable="d"
        Title="Alertimer" SizeToContent="Height" Width="700" MinWidth="700" ResizeMode="CanMinimize">
    <Window.Resources>
        <Style TargetType="TextBox">
            <Setter Property="Height" Value="25"></Setter>
            <Setter Property="TextWrapping" Value="Wrap"></Setter>
            <Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel Name="Labels" Orientation="Horizontal">
            <TextBox Text="Client" VerticalAlignment="Top" Margin="30,15,0,0" Width="130" Height="30" FontSize="12" VerticalContentAlignment="Center" BorderBrush="{x:Null}" TextWrapping="Wrap" IsEnabled="False"/>
            <TextBox Text="Ticket #" VerticalAlignment="Top" Margin="10,15,0,0" Width="80" Height="30" FontSize="12" VerticalContentAlignment="Center" BorderBrush="{x:Null}" TextWrapping="Wrap" IsEnabled="False"/>
            <TextBox Text="Time of last update" VerticalAlignment="Top" Margin="10,15,0,0" Width="180" Height="30" FontSize="12" FontStretch="Condensed" VerticalContentAlignment="Center" BorderBrush="{x:Null}" TextWrapping="Wrap" IsEnabled="False"/>
            <TextBox Text="Next update within?..." VerticalAlignment="Top" Margin="10,15,0,0" Width="125" Height="30" FontSize="12" VerticalContentAlignment="Center" BorderBrush="{x:Null}" TextWrapping="Wrap" IsEnabled="False"/>
            <TextBox Text="Add/Remove entry" VerticalAlignment="Top" Margin="10,15,0,0" Width="75" Height="30" FontSize="10" VerticalContentAlignment="Center" BorderBrush="{x:Null}" TextWrapping="Wrap" IsEnabled="False"/>
        </StackPanel>
        <StackPanel Name="Column" Orientation="Vertical" Margin="0,0,0,30">
            <StackPanel Name="Controls" Orientation="Horizontal" Margin="0,0,0,5">
                <TextBox Name="Client" Margin="30,50,0,0" Text="LSC Communications" GotFocus="TextBox_GotFocus" Width="130" FontSize="11" VerticalContentAlignment="Center"/>
                <TextBox Name="Ticket" Margin="10,50,0,0" Text="INC0123456" GotFocus="TextBox_GotFocus" Width="80" FontSize="11" VerticalContentAlignment="Center"/>
                <xctk:DateTimePicker Name="LastUpdate" Height="25" Width="180" Margin="10,50,0,0" DisplayDefaultValueOnEmptyText="True" Format="Custom" FormatString="dd MMMM HH:mm tt" TimePickerShowButtonSpinner="False"></xctk:DateTimePicker>
                <ComboBox Name="Within" SelectedValuePath="Content" IsEditable="True" IsReadOnly="True" Text="Select time period" Margin="10,50,0,0" Width="125" Height="25" VerticalContentAlignment="Center">
                    <ComboBoxItem Content="Within 1 hour"/>
                    <ComboBoxItem Content="Within 2 hours"/>
                    <ComboBoxItem Content="Within 3 hours"/>
                    <ComboBoxItem Content="Within 4 hours"/>
                    <ComboBoxItem Content="Within 5 hours"/>
                    <ComboBoxItem Content="Within 6 hours"/>
                </ComboBox>
                <Button Name="Timer" Content="Add timer" Click="addNewTimer" Margin="10,50,0,0" Width="75" FontSize="11" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Globalization;
using Xceed.Wpf.Toolkit;

namespace Alertimer
{
    public partial class MainWindow : Window
    {
        DispatcherTimer _timer;
        System.Media.SoundPlayer warning;

        public MainWindow()
        {
            InitializeComponent();
        }

        public void TextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            tb.Text = string.Empty;
            tb.GotFocus -= TextBox_GotFocus;
        }

        private void addNewTimer(object sender, EventArgs e)
        {
            Button Timer = sender as Button;
            StackPanel stkButtonParent = Timer.Parent as StackPanel;
            StackPanel stkCover = stkButtonParent.Parent as StackPanel;
            StackPanel newRow = NewRow();
            stkCover.Children.Add(newRow);
        }

        private StackPanel NewRow() {

            double hoursWithin = 0;

            switch (Within.SelectedValue)
            {
                case "Within 1 hour":
                    hoursWithin = 1;
                    break;
                case "Within 2 hours":
                    hoursWithin = 2;
                    break;
                case "Within 3 hours":
                    hoursWithin = 3;
                    break;
                case "Within 4 hours":
                    hoursWithin = 4;
                    break;
                case "Within 5 hours":
                    hoursWithin = 5;
                    break;
                case "Within 6 hours":
                    hoursWithin = 6;
                    break;
            }

            StackPanel newAlert = new StackPanel();
            newAlert.Orientation = Orientation.Horizontal;
            newAlert.Margin = new Thickness(0, 5, 0, 0);

            TextBox NewClient = new TextBox();
            NewClient.Text = Client.Text;
            NewClient.Width = 130;
            NewClient.Margin = new Thickness(30, 0, 0, 0);
            NewClient.Style = (Style)Application.Current.Resources["TextBoxes"];
            NewClient.IsEnabled = false;

            TextBox NewTicket = new TextBox();
            NewTicket.Text = Ticket.Text;
            NewTicket.Width = 80;
            NewTicket.Margin = new Thickness(10,0,0,0);
            NewTicket.Style = (Style)Application.Current.Resources["TextBoxes"];
            NewTicket.IsEnabled = false;

            try
            {
                DateTime nextTimeTest = DateTime.ParseExact(LastUpdate.Text, "dd MMMM HH:mm tt", CultureInfo.InvariantCulture).AddHours(hoursWithin);
            }
            catch (Exception)
            {
                System.Windows.MessageBox.Show("You forgot to input the time of the last update!", "Whoops!", MessageBoxButton.OK, MessageBoxImage.Warning);
            }

            DateTime nextTime = DateTime.ParseExact(LastUpdate.Text, "dd MMMM HH:mm tt", CultureInfo.InvariantCulture).AddHours(hoursWithin);

            String Today = DateTime.Now.ToString("dd MMMM HH:mm tt");
            DateTime currentTime = DateTime.ParseExact(Today,"dd MMMM HH:mm tt", CultureInfo.InvariantCulture);

            TimeSpan timeLeft = nextTime - currentTime;

            string[] timeLeftElements = timeLeft.ToString().Split(':');

            int hours = Convert.ToInt32(timeLeftElements[0]);
            int minutes = Convert.ToInt32(timeLeftElements[1]);
            int seconds = Convert.ToInt32(timeLeftElements[2]);

            TextBox TillNextUpdate = new TextBox();
            TillNextUpdate.Margin = new Thickness(10, 0, 0, 0);
            TillNextUpdate.Width = 315;
            TillNextUpdate.Style = (Style)Application.Current.Resources["TextBoxes"];
            TillNextUpdate.FontSize = 16;
            TillNextUpdate.Name = "timeLeft";

            Button NewRowDelete = new Button();
            NewRowDelete.Content = "Remove";
            NewRowDelete.Width = 75;
            NewRowDelete.Height = 25;
            NewRowDelete.Margin = new Thickness(10, 0, 0, 0);
            NewRowDelete.Click += RemoveTimer;

            newAlert.Children.Add(NewClient);
            newAlert.Children.Add(NewTicket);
            newAlert.Children.Add(TillNextUpdate);
            newAlert.Children.Add(NewRowDelete);

            timeLeft = new TimeSpan(hours, minutes, seconds);
            _timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
            {
                TillNextUpdate.Text = timeLeft.ToString("c");

                if (timeLeft == TimeSpan.Zero)
                {
                    _timer.Stop();
                }
                else
                {
                    timeLeft = timeLeft.Add(TimeSpan.FromSeconds(-1));
                }

                if (TillNextUpdate.Text == "00:20:00")
                {
                    TillNextUpdate.Background = Brushes.Yellow;
                    warning = new System.Media.SoundPlayer(Properties.Resources.alert20);
                    warning.Play();
                }
                else if (TillNextUpdate.Text == "00:15:00")
                {
                    TillNextUpdate.Background = Brushes.Orange;
                    TillNextUpdate.FontWeight = FontWeights.Bold;
                    warning = new System.Media.SoundPlayer(Properties.Resources.alert15);
                    warning.Play();
                }
                else if (TillNextUpdate.Text == "00:10:00")
                {
                    TillNextUpdate.Background = Brushes.Red;
                    warning = new System.Media.SoundPlayer(Properties.Resources.alert10);
                    warning.Play();
                }
            }, Application.Current.Dispatcher);

            _timer.Start();

            Frame.MinHeight = Frame.MinHeight + 25;

            return newAlert;
        }
        private void RemoveTimer(object sender, EventArgs e)
        {
            Button Delete = sender as Button;
            StackPanel stkButtonParent = Delete.Parent as StackPanel;
            StackPanel stkCover = stkButtonParent.Parent as StackPanel;

            stkCover.Children.Remove(stkButtonParent);
            Frame.MinHeight = Frame.MinHeight - 25;
        }
    }
}

person ProudRambo    schedule 02.12.2019    source источник


Ответы (1)


вам нужно хранить DispatcherTimer. в методе NewRow(),

        _timer.Start();
        newAlert.Tag = _timer; // store _timer !
        Frame.MinHeight = Frame.MinHeight + 25;

        return newAlert;

в методе RemoveTimer получите таймер и остановите()

    private void RemoveTimer(object sender, EventArgs e)
    {
        Button Delete = sender as Button;
        StackPanel stkButtonParent = Delete.Parent as StackPanel;
        StackPanel stkCover = stkButtonParent.Parent as StackPanel;
        DispatcherTimer timer = stkButtonParent.Tag as DispatcherTimer; 
        timer.Stop(); // stop timer
        stkCover.Children.Remove(stkButtonParent);
        Frame.MinHeight = Frame.MinHeight - 25;
    }

удачи!

person Byoung Sam Moon    schedule 03.12.2019