Обратный отсчет до даты в приложении Windows Phone

1

Я создаю обратный отсчет до определенной даты. Осталось несколько дней, оставшиеся часы и оставшиеся минуты должны отображаться в текстовом блоке.

Сделал плоский дизайн в XAML, знает, как рассчитать промежуток времени. Теперь я нуждаюсь в реальном обновлении, пока приложение работает.

Мой Xaml

<Grid x:Name="myLayoutGrid"
      Background="CadetBlue" Margin="0,-26.667,0,-0.333"
      >

    <TextBlock x:Name="countDays" 
               HorizontalAlignment="Left" 
               Margin="45,150,0,0" 
               TextWrapping="Wrap" 
               Text="Dagen" 
               VerticalAlignment="Top"
               FontFamily="Tahoma"
               FontSize="34" Loaded="countDays_Loaded"/>
    <TextBlock x:Name="countHours" 
               HorizontalAlignment="Left" 
               Margin="45,200,0,0" 
               TextWrapping="Wrap" 
               Text="Uur" 
               VerticalAlignment="Top" 
               FontFamily="Tahoma"
               FontSize="30" Loaded="countHours_Loaded"/>
    <TextBlock x:Name="countMinutes" 
               HorizontalAlignment="Left"
               Margin="45,250,0,0" 
               TextWrapping="Wrap" 
               Text="Minuten" 
               VerticalAlignment="Top"
               FontFamily="Tahoma"
               FontSize="26" Loaded="countMinutes_Loaded"/>

Мой код;

private void countDays_Loaded(object sender, RoutedEventArgs e)
    {
        DateTime end = DateTime.Parse("01/01/2016 15:00");
        DateTime start = DateTime.Now;

        TimeSpan ts = end - start;

        countDays.Text = string.Format("{0} Dagen", ts.Days);



    }

    private void countHours_Loaded(object sender, RoutedEventArgs e)
    {
        DateTime end = DateTime.Parse("01/01/2016 15:00");
        DateTime start = DateTime.Now;

        TimeSpan ts = end - start;

        countHours.Text = string.Format("{0} Uur", ts.Hours);

    }

    private void countMinutes_Loaded(object sender, RoutedEventArgs e)
    {

        DateTime end = DateTime.Parse("01/01/2016 15:00");
        DateTime start = DateTime.Now;

        TimeSpan ts = end - start;

        countMinutes.Text = string.Format("{0} Minuten", ts.Minutes);
    }

После того, как я понял код и почему я должен использовать этот код, я хотел бы очистить свой код (поместить таймер в класс). После этого и я изучил приложение HUB, я буду использовать его в привязке.

Любая помощь будет большой.

  • 0
    Вы не должны сильно редактировать начальный вопрос, так как он выводит ответы из контекста, и тогда он никому не нужен. Открытие нового вопроса совершенно нормально.
Теги:
xaml
wpf
countdown
windows-phone-8

2 ответа

0
Лучший ответ

Для периодического обновления оставшегося времени вам понадобится какой-то таймер. Попробуйте следующий подход:

public partial class MainWindow : Window
{
    private readonly DateTime _endDate;
    private readonly DispatcherTimer _timer;

    public MainWindow()
    {
        InitializeComponent();

        _endDate = new DateTime(2016, 1, 1, 15, 0, 0);
        _timer = new DispatcherTimer();
        _timer.Tick += CountDown;
        _timer.Interval = TimeSpan.FromMinutes(1);
        _timer.Start();
    }

    private void CountDown(object sender, EventArgs e)
    {
        var remainingTime = _endDate.Subtract(DateTime.Now);

        countDays.Text = string.Format("{0} Dagen", remainingTime.Days);
        countHours.Text = string.Format("{0} Uur", remainingTime.Hours);
        countMinutes.Text = string.Format("{0} Minuten", remainingTime.Minutes);
    }
}

Чтобы сделать компиляцию кода, удалите Loaded="countX_Loaded" событий Loaded="countX_Loaded" из ваших Loaded="countX_Loaded" блоков в вашем XAML.

<Window x:Class="Stackoverflow28009341.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="myLayoutGrid" Background="CadetBlue" Margin="0,-26.667,0,-0.333">
        <TextBlock x:Name="countDays" 
               HorizontalAlignment="Left" 
               Margin="45,150,0,0" 
               TextWrapping="Wrap" 
               Text="Dagen" 
               VerticalAlignment="Top"
               FontFamily="Tahoma"
               FontSize="34"/>
        <TextBlock x:Name="countHours" 
               HorizontalAlignment="Left" 
               Margin="45,200,0,0" 
               TextWrapping="Wrap" 
               Text="Uur" 
               VerticalAlignment="Top" 
               FontFamily="Tahoma"
               FontSize="30"/>
        <TextBlock x:Name="countMinutes" 
               HorizontalAlignment="Left"
               Margin="45,250,0,0" 
               TextWrapping="Wrap" 
               Text="Minuten" 
               VerticalAlignment="Top"
               FontFamily="Tahoma"
               FontSize="26"/>
    </Grid>
</Window>
  • 0
    Таймер в codebehind может быть самой простой, быстрой и простой реализацией, если вы новичок в разработке WP, разделение задач и шаблонов проектирования. Тем не менее, один человек должен отойти от разработки кода.
  • 0
    @Mikko это правда. Ваш подход, безусловно, является более перспективным в этом отношении.
Показать ещё 8 комментариев
1

Вы должны использовать шаблон MVVM при разработке приложений для WP8 с использованием С#/XAML.

Это означает, что вы создаете View (например, XAML окна), а затем отделенный контекст для данных, так ли именем ViewModel. Когда данные изменяются, вам необходимо уведомить представление об изменениях, реализовав интерфейс INotifyPropertyChanged.

Для периодических изменений вы должны использовать Асинхронный шаблон на основе задач. Таким образом, ваш поток пользовательского интерфейса не блокируется. Это было бы проще всего с помощью Task.

Конечно, есть несколько других способов сделать это, но это то, что я бы рекомендовал.

Тогда ваше приложение может выглядеть примерно так:

MainWindow.xaml

<!-- This would be <phone:PhoneApplicationPage in WP8 app -->
<!-- e.g. phone:PhoneApplicationPage x:Class="PhoneApp1.MainPage"-->
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        Title="MainWindow"
        Height="116"
        Width="250">
    <Window.DataContext>
        <wpfApplication1:MainViewModel />
    </Window.DataContext>

    <StackPanel VerticalAlignment="Center">
        <!-- Bind displayed text to MainViewModel CountDown property -->
        <!-- This way it automically updates the TextBlock whenever value is changed -->
        <TextBlock Text="{Binding CountDown}" FontSize="24" TextAlignment="Center" />
    </StackPanel>        
</Window>

MainWindow.xaml.cs

// No code added here, this is the initial class structure.
// This needs to be in same namespace as MainWindow/Page XAML (partial)
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

MainViewModel.cs

// This would be plain C# class in WP8, too
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace WpfApplication1
{
    public class MainViewModel : INotifyPropertyChanged
    {
        // This event takes care of notifying the page so it updates
        public event PropertyChangedEventHandler PropertyChanged;
        private string _countDown;

        public MainViewModel()
        {
            // Day to countdown to
            DateTime targetDate = DateTime.Now.AddDays(5d);

            // Start new thread
            Task.Factory.StartNew(() =>
                {
                    // Loop until target date and update value every second
                    while (DateTime.Now <= targetDate)
                    {
                        // Format and set new value
                        CountDown = (targetDate - DateTime.Now).ToString("d'd 'h'h 'm'm 's's'");
                        Thread.Sleep(1000);
                    }
                    // Final value
                    CountDown = "It tiem!";
                });
        }

        // Value displayed in Page TextBlock
        public string CountDown
        {
            get { return _countDown; }
            set { _countDown = value; OnPropertyChanged();}
        }

        // This is INotifyPropertyChanged implementation
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) 
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Это дает вам счетчик, как показано ниже, который обновляется один раз в секунду и не задерживает пользовательский интерфейс.

Изображение 174551 (пример для приложения.NET 4.5 WPF, но он должен быть 99%... 100% для приложений Windows Phone).

Вместо того, чтобы просто в while циклы вы можете взять более длинный путь и заменить его с помощью таймера, если вы хотите, заменив Task.Factory.StartNew блок с

var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
timer.Tick += (sender, args) =>
    {
        DateTime now = DateTime.Now;
        int difference = (int) (targetDate - now).TotalSeconds;
        CountDown = difference >= 0 ? 
                    (targetDate - now).ToString("d'd 'h'h 'm'm 's's'") : 
                    "It tiem!";
        if (difference < 0)
            timer.Stop();
    };
timer.Start();
  • 0
    возможно, это лучшая реализация, но мои знания недостаточно велики, чтобы это исправить. Я строю из "Blank App" в визуальной студии.
  • 0
    Пример завершен, вы можете изменить его в соответствии с вашими потребностями.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню