我正在使用DataTemplate在列表框中显示项目(通过数据绑定从类中)。这个类还包含日期和时间,我正在使用转换器将此日期/时间转换为相对时间(xx分钟前),然后显示在TextBlock中。到目前为止一切都很棒。
问题在于我不知道如何保持这个相对时间更新(它们都停留在生成的值上,例如“1秒前”)。我可以使用ListBox.Items.Refresh(),但这也会重新运行我为项目设置的动画。
有什么想法吗?
提前致谢!
答案 0 :(得分:0)
让您的模型实现INotifyPropertyChanged
。如果正确设置了双向绑定,则只要想要更新的属性发生更改,就调用OnPropertyChanged
传递属性名称。这将警告任何人正在查看该属性的更改(即您的视图因此双向绑定要求)值已更改并且需要更新。
public string Name
{
get { return m_Name; }
set
{
OnPropertyChanged(Name);
m_Name = value;
}
}
<强>更新强>
使用计时器。我不会从Dave那里偷取来源所以这里是他answer链接到一个非常相似的问题。在timer_Tick
方法中,进行相对时间计算。这将每秒更新您的GUI。
答案 1 :(得分:0)
您需要为绑定的属性实施INotifyPropertyChanged
或DependencyProperty
才能查看更新。
DependencyProperty
是WPF中的首选方法,因为它将在运行时产生更好的性能。 Here is the documentation,包括如何创建一个的示例。
答案 2 :(得分:0)
好吧这可能不是最优雅的解决方案(我很确定),但是现在我使用ListBox的ScrollChanged事件以可接受的结果完成此操作,只需为每个可见项目的时间添加1毫秒,导致相对时间更新;)每次向列表框添加内容时都会调用代码,并且只影响当前可见的项目(类似于VirtualizingStackPanel):)
int VO = 0; // I think that this was protection for when a load of items are added at the beginning. Maybe you can do fine without it.
private void HomeList_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
int v = (int)e.VerticalOffset;
if (HomeList.Items.Count > 0 && v != VO) // Maybe you can do fine without VO.
{
for (int i = 0; i < e.ViewportHeight; i++)
{
// Add 1 millisecond to the item's time here
}
VO = v; // Maybe you can do fine without VO.
}
}
答案 3 :(得分:0)
我刚才遇到了同样的问题,我通过为这些项创建一个ViewMode来解决它。
public class MyItem
{
public DateTime { get; set; }
}
public class MyItemViewModel : INotifyPropertyChanged
{
private string relativeTime;
public string RelativeTime
{
get { return relativeTime; }
set
{
relativeTime = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("RelativeTime"));
}
}
public DateTime Date { get; set; }
public static implicit operator MyItemViewModel(MyItem item)
{
return new MyItemViewModel { Date = item.Date }
}
}
然后使用计时器更新它们。
updateRelativeTimeString = new Timer(s =>
Items.ForEach(
item => item.RelativeTime = item.Date.ToRelativeTime()),
null,
0,
5000);
使用两种扩展方法(IEnumerable.ForEach和DateTime.ToRelativeTime)
答案 4 :(得分:0)
我决定发布我自己的解决方案,因为我认为这是最简单的,并且需要的代码比我见过的其他代码少得多。
//AbstractViewModel implements INotifyPropertyChanged
public class MyObject : AbstractViewModel
{
private DateTime date = DateTime.UtcNow;
public DateTime Date
{
get
{
return date;
}
set
{
date = value;
OnPropertyChanged("Date");
}
}
public MyObject()
{
Timer t = new Timer();
t.Interval = 1000; //Update every second
t.Elapsed += T_Elapsed;
t.Enabled = true;
}
private void T_Elapsed(object sender, ElapsedEventArgs e)
{
OnPropertyChanged("Date");
}
}
然后,您将在转换器中执行相对时间操作:
using System;
using System.Globalization;
using System.Windows.Data;
namespace MyConverters
{
[ValueConversion(typeof(DateTime), typeof(string))]
public class RelativeTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime Date = (DateTime)value;
if (Date == null) return "never";
return Utility.RelativeTime(Date);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
将转换器添加到绑定:
<Run Text="{Binding Date, Converter={StaticResource RelativeTimeConverter}}"/>
要切换对象是否应该勾选,您可以在对象类中定义一个额外的构造函数或标志,指示是否启用了此类行为。这样,如果您的应用程序支持更改日期格式,您可以简单地迭代对象,检查每个标记,并删除(或交换)绑定的现有转换器。