Как привязать зависящее от времени свойство всех элементов в ObservableCollection в TextBox? - PullRequest
0 голосов
/ 26 мая 2020

У меня есть множество задач (экземпляров TaskClass), хранящихся в ObservableCollection с именем TaskCollection. В классе TaskClass было свойство TimeLeft, которое динамически изменялось при выполнении задачи.

class TaskClass:INotifyPropertyChanged
{
    TimeSpan TimeLeft{get;set;}
}

Когда выполнялась одна или несколько задач, пользователь мог добавлять новые задачи в TaskCollection. Когда задача выполняется, ее свойство TimeLeft изменяется (увеличивается или уменьшается).

A TextBox использовался в пользовательском интерфейсе для отображения общего времени, необходимого для всех задач. Я пробовал использовать мульти-привязку как к TaskCollection, так и к TaskCollection.Count. Общее время будет отображаться в текстовом поле сразу после добавления / удаления задач пользователем. Но когда существующая задача запущена (свойство TimeLeft изменяется), TextBox не может уведомить. ?

1 Ответ

1 голос
/ 26 мая 2020

Но когда существующая задача запущена (свойство TimeLeft изменяется), TextBox не может уведомить.

Это потому, что нет уведомления ни для каких данных - связанные свойства, когда установлено отдельное свойство TimeLeft.

Что вам нужно сделать, так это добавить свойство в модель представления, которая возвращает сумму всех TimeSpan s. Затем вы должны реализовать logi c, чтобы установить это свойство в модели представления, которой оно принадлежит. Примерно так:

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel()
    {
        Tasks.CollectionChanged += OnTasksCollectionChanged;
    }

    public ObservableCollection<TaskClass> Tasks { get; } = 
        new ObservableCollection<TaskClass>();

    public TimeSpan TotalTimeLeft => new TimeSpan(Tasks.Sum(x => x.TimeLeft.Ticks));

    private void OnTasksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
            foreach (object task in e.NewItems)
                (task as INotifyPropertyChanged).PropertyChanged
                    += new PropertyChangedEventHandler(OnTaskPropertyChanged);

        if (e.OldItems != null)
            foreach (object task in e.OldItems)
                (task as INotifyPropertyChanged).PropertyChanged
                    -= new PropertyChangedEventHandler(OnTaskPropertyChanged);

        NotifyPropertyChanged(nameof(TotalTimeLeft));
    }

    private void OnTaskPropertyChanged(object sender, PropertyChangedEventArgs e) =>
        NotifyPropertyChanged(nameof(TotalTimeLeft));

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
...