繁体   English   中英

使用WPF DataTemplate更新相对时间

[英]Updating relative time with WPF DataTemplate

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

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

有任何想法吗?

提前致谢!

让您的模型实现INotifyPropertyChanged 如果您的双向绑定设置正确,则每当您要更新的属性发生更改时,请调用OnPropertyChanged并将其传递给属性名称。 这将提醒正在查看该属性更改的任何人(即您的视图,因此具有双向绑定要求)该值已更改并且需要更新。

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

更新:

使用计时器。 我不会从戴夫那里窃取消息来源,因此这是他对类似问题的回答的链接。 在您的timer_Tick方法中进行相对时间计算。 这将每秒更新一次GUI。

您需要为要绑定的属性实现INotifyPropertyChangedDependencyProperty才能查看更新。

DependencyProperty是WPF中的首选方法,因为它将在运行时带来更好的性能。 这里是文档 ,包括如何创建示例的示例。

好的,这可能不是最优雅的解决方案(我很确定),但是到目前为止,我已经使用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.
    }
}

我决定发布自己的解决方案,因为我认为它是最简单的,并且所需的代码比我所看到的其他代码少得多。

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

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

我现在遇到了同样的问题,我通过为这些项目创建一个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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM