windows phone 应用中的倒计时
Countdown to date in windows phone app
我正在为特定日期创建倒计时。剩余天数、剩余小时数和剩余分钟数必须显示在文本块中。
在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);
}
在理解了代码以及为什么要使用该代码之后,我想清理我的代码(将计时器放在 class 中)。之后我研究了HUB应用程序,我将在绑定元素中使用它。
任何帮助都会很棒。
您需要某种计时器来定期刷新剩余时间。尝试以下方法:
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);
}
}
要编译代码,请从 XAML 中的文本块中删除 Loaded="countX_Loaded"
事件处理程序。
<Window x:Class="Whosebug28009341.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>
当您使用 C# 为 WP8 开发应用程序时,您应该使用 MVVM 模式/XAML。
这意味着您创建一个 View
(例如 XAML Window),然后为其数据创建一个单独的上下文,名为 ViewModel
。每当数据发生更改时,您需要通过实现 INotifyPropertyChanged
接口来通知视图更改。
要进行定期更改,您应该使用 Task-based 异步模式。这样你的 UI 线程就不会被阻塞。使用 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's 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's tiem!";
});
}
// Value displayed in Page's 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));
}
}
}
这使您的计数器看起来如下所示,它每秒更新一次并且不会冻结 UI。
(示例适用于 .NET 4.5 WPF 应用程序,但对于 Windows Phone 应用程序,它应该是 99%...100% 相同)。
除了简单的 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's tiem!";
if (difference < 0)
timer.Stop();
};
timer.Start();
我正在为特定日期创建倒计时。剩余天数、剩余小时数和剩余分钟数必须显示在文本块中。
在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);
}
在理解了代码以及为什么要使用该代码之后,我想清理我的代码(将计时器放在 class 中)。之后我研究了HUB应用程序,我将在绑定元素中使用它。
任何帮助都会很棒。
您需要某种计时器来定期刷新剩余时间。尝试以下方法:
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);
}
}
要编译代码,请从 XAML 中的文本块中删除 Loaded="countX_Loaded"
事件处理程序。
<Window x:Class="Whosebug28009341.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>
当您使用 C# 为 WP8 开发应用程序时,您应该使用 MVVM 模式/XAML。
这意味着您创建一个 View
(例如 XAML Window),然后为其数据创建一个单独的上下文,名为 ViewModel
。每当数据发生更改时,您需要通过实现 INotifyPropertyChanged
接口来通知视图更改。
要进行定期更改,您应该使用 Task-based 异步模式。这样你的 UI 线程就不会被阻塞。使用 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's 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's tiem!";
});
}
// Value displayed in Page's 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));
}
}
}
这使您的计数器看起来如下所示,它每秒更新一次并且不会冻结 UI。
除了简单的 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's tiem!";
if (difference < 0)
timer.Stop();
};
timer.Start();