2009-12-15 22 views
1

我正在使用DataTemplate在列表框中显示项目(通过数据绑定从一个类)。这个类还包含日期和时间,我使用转换器将此日期/时间转换为相对时间(xx分钟前),然后将其显示在TextBlock中。到目前为止,一切都很好。使用WPF DataTemplate更新相对时间

问题是我不知道如何保持这个相对时间更新(它们都被卡在生成的值上,例如“1秒前”)。我可以使用ListBox.Items.Refresh(),但是它也会重新运行我为这些项目设置的动画。

任何想法?

在此先感谢!

+0

确定这个INotifyPropertyChanged和DependencyProperty的东西是我的头,所以我改变了用户界面一点点,以解决这个问题。可能稍后会回到这个位置。谢谢:) – 2009-12-16 16:14:31

回答

0

让你的模型实现INotifyPropertyChanged。如果您的双向绑定设置正确,请拨打OnPropertyChanged将属性名称传递给您希望更新的属性更改。这会提醒任何人查看对该属性的更改(即您的视图因此是双向约束要求),该值已更改且需要更新。

public string Name 
{ 
    get { return m_Name; } 
    set 
    { 
     OnPropertyChanged(Name); 
     m_Name = value; 
    } 
} 

更新:

使用一个定时器。我不会从戴夫那里窃取信息,所以这里有一个与他的answer相关的链接,这个问题非常类似。在你的timer_Tick方法做你的相对时间计算。这将每秒更新您的GUI。

+0

但是,如果每个项目的时间没有改变,OnPropertyChanged会工作吗? (这是在服务器上的项目创建时间) – 2009-12-16 15:37:27

+0

因此,模型上的时间属性不会更改。我假设你正在使用DateTime.Now进行相对计算,并且你只是想计算主动更新,对吗? – Ragepotato 2009-12-16 18:20:57

+0

基本上是的:) – 2009-12-16 18:26:00

0

您需要实施INotifyPropertyChangedDependencyProperty以查看您要绑定的媒体资源才能看到更新。

DependencyProperty是WPF中的首选方法,因为它会在运行时带来更好的性能。其中包括如何创建一个示例。

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. 
    } 
} 
+0

您不应该更改DateTime值。你需要的是一个转换器。 – 2016-04-20 19:46:16

0

我有同样的问题刚才我通过为这些项目创建一个ViewModel来解决它。

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)

+0

使用定时器JUST来提高属性更改事件并使用绑定到该值的转换器会更有意义吗?只要计时器引发PropertyChanged事件,转换器就会自动提取何时转换并输出新值。 – 2016-04-20 19:48:14

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}}"/> 

还可以切换该对象是否应该打勾,你可以在对象类中定义一个额外的构造函数或标志,指示是否启用了此类行为。这样,如果您的应用程序支持更改日期格式,您可以简单地迭代您的对象,检查每个标志,并删除(或交换)绑定的现有转换器。