WPF Привязка даты и времени относительно текущего времени

Я ищу способ связать дату и время, но отобразить разницу с текущим временем.

Вот код С#:

public partial class MainWindow : Window
{ 

    public ObservableCollection<Information> Informations;

    public MainWindow()
    {
        InitializeComponent();

        Informations = new ObservableCollection<Information>
        {
            new Information() { When = DateTime.Now, What = "A first information" },
            new Information() { When = DateTime.Now, What = "Another information" },
            new Information() { When = DateTime.Now, What = "An other information" }
        };

       ltvInfos.ItemsSource = Informations;

    }
}


public class Information : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = "")
    {
        var handler = PropertyChanged;
        handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    public string What
    {
        get { return what; }
        set { what = value; OnPropertyChanged(); }
    }
    private string what;


    public DateTime When
    {
        get { return when; }
        set { when = value; OnPropertyChanged(); }
    }
    private DateTime when;

}

И WPF:

 <ListView x:Name = "ltvInfos">
      <ListView.ItemTemplate>
                
           <DataTemplate>
                <WrapPanel Orientation = "Horizontal">
                     <TextBlock Text = "{Binding When}" Margin = "5,0"/>
                     <TextBlock Text = "{Binding What}" />
                </WrapPanel>
           </DataTemplate>
                
      </ListView.ItemTemplate>
 </ListView>`

Вот результат:

И я ищу, чтобы отобразить что-то вроде этого:

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

Это один из простых способов. Почему бы вам это не реализовать?

emoacht 20.04.2024 15:24

@emoacht, потому что мне кажется сложным обновлять каждую секунду мою коллекцию информации, которая будет содержать тысячи объектов. Если есть способ просто «перевести» это с помощью своего рода привязки, это будет гораздо оптимальнее!

R. Douan 20.04.2024 17:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

1000 объектов – не проблема. Это станет заметно только после того, как вы достигнете отметки в 1 000 000, и в этот момент вам придется пересмотреть свой дизайн.

Значит, не существует «простого способа» естественным образом отобразить разницу во времени без использования определенного свойства?

R. Douan 20.04.2024 19:04

Нет, вам нужно закодировать это самостоятельно.

LazZ 20.04.2024 19:13

Хорошо. Есть ли способ получить информацию о том, что отображается список? Например, с логической привязкой IsDisplayed, и когда это логическое значение истинно, время также включено.

R. Douan 20.04.2024 19:18

Да, вы можете привязать свойство Visibility к своему TextBlock и добавить в свой класс Information свойство, которое возвращает System.Windows.Visibility.

LazZ 20.04.2024 20:00

Видимость будет ложной, если я прокрутлю, а линия объекта не отобразится?

R. Douan 20.04.2024 22:30
Ответ принят как подходящий

Если вы хотите сэкономить ресурсы (нужно ли вам это делать, это другая история), вы можете: 1) поместить логику таймера в поле зрения, чтобы избежать обновления при каждом такте модели представления, 2) разделить таймер между экземплярами, 3) Используйте виртуализацию.

Допустим, создайте пользовательский TextBlock, статический член которого имеет таймер, и поделитесь им между экземплярами.

public class TimerTextBlock : TextBlock
{
    private static DispatcherTimer _timer;

    static TimerTextBlock()
    {
        _timer = new() { Interval = TimeSpan.FromSeconds(1) };
        _timer.Start();
    }

    public DateTime Time
    {
        get { return (DateTime)GetValue(TimeProperty); }
        set { SetValue(TimeProperty, value); }
    }
    public static readonly DependencyProperty TimeProperty =
        DependencyProperty.Register(
            "Time",
            typeof(DateTime),
            typeof(TimerTextBlock),
            new PropertyMetadata(default(DateTime), OnTimeChanged));

    private static void OnTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TimerTextBlock)d).IsRunning = ((DateTime)e.NewValue != default);
    }

    private bool _isRunning;
    public bool IsRunning
    {
        get => _isRunning;
        set
        {
            if (_isRunning != value)
            {
                _isRunning = value;
                if (_isRunning)
                {
                    _timer.Tick += OnTick;
                }
                else
                {
                    _timer.Tick -= OnTick;
                }
            }
        }
    }

    private void OnTick(object? sender, EventArgs e)
    {
        this.Text = (DateTime.Now - Time).ToString(/* Specify text format */);
    }
}

И если предположить, что ваша модель представления имеет коллекцию DateTime с именем «Times» как общедоступное свойство только для чтения, простой ListBox, который принимает эту коллекцию, будет следующим:

<ListBox ItemsSource = "{Binding Times}"
         VirtualizingStackPanel.IsVirtualizing = "True"
         VirtualizingStackPanel.VirtualizationMode = "Recycling">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <local:TimerTextBlock Time = "{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Это очень хороший способ, тай!

R. Douan 21.04.2024 09:29

Другие вопросы по теме