Привязка к свойствам, зависящим от времени - PullRequest
15 голосов
/ 25 мая 2011

Некоторое время назад я написал небольшое приложение, похожее на виджет, которое должно было отслеживать задачи, для каждой задачи был установлен крайний срок DateTime, теперь, если вы хотите отобразить, сколько времени осталось до истечения указанного вами срока.может потребоваться привязать к «виртуальному» (* curses the virtual ключевое слово *) следующее:

public TimeSpan TimeLeft
{
    get { return Deadline - DateTime.Now; }
}

Очевидно, что в теории это свойство меняет каждый тик, и вы хотитевремя от времени обновляйте свой пользовательский интерфейс (например, периодически выкачивая событие PropertyChanged для этого свойства).

Когда я писал виджет, я каждую минуту обновлял весь список задач, но это вряд ли идеально, посколькуесли пользователь взаимодействует с каким-либо элементом (например, набрав в TextBox, который связывается с Comments -свойством), который будет резко прерываться, а обновления источника теряются.

Так что может быть лучшим подходомобновить пользовательский интерфейс, если у вас есть свойства, зависящие от времени, как это?

( Кстати, я больше не использую это приложение, просто подумал, что это avочень интересный вопрос )

Ответы [ 3 ]

4 голосов
/ 25 мая 2011

Таймер - единственный способ, о котором я могу думать. Поскольку это интересный вопрос, я вставлю свой .02. Я бы инкапсулировал его, выполнив что-то вроде этого:

public class CountdownViewModel : INotifyPropertyChanged
{
    Func<TimeSpan> calc;
    DispatcherTimer timer;

    public CountdownViewModel(DateTime deadline)
        : this(() => deadline - DateTime.Now)
    {
    }

    public CountdownViewModel(Func<TimeSpan> calculator)
    {
        calc = calculator;

        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += timer_Tick;
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        var temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs("CurrentValue"));
        }
    }

    public TimeSpan CurrentValue
    {
        get
        {
            var result = calc();
            if (result < TimeSpan.Zero)
            {
                return TimeSpan.Zero;
            }
            return result;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class MyViewModel
{
    public CountdownViewModel DeadlineCountdown { get; private set; }

    public DateTime Deadline { get; set; }

    public MyViewModel()
    {
        Deadline = DateTime.Now.AddSeconds(200);
        DeadlineCountdown = new CountdownViewModel(Deadline);
    }
}

Тогда вы можете напрямую связать с DeadlineCountdown.CurrentValue или создать CountdownView. Вы можете переместить таймер на CountdownView, если хотите. Вы можете использовать статический таймер, чтобы все они обновлялись одновременно.

Редактировать

Если Deadline собирается измениться, вы должны построить обратный отсчет так:

DeadlineCountdown = new CountdownViewModel(() => this.Deadline - DateTime.Now);
3 голосов
/ 25 мая 2011

Я думаю, что то, что вы сказали в первом абзаце после примера кода, - единственный разумный способ заставить это работать в WPF. Установите таймер, который просто вызывает PropertyChanged для свойства TimeLeft. Интервал будет варьироваться в зависимости от вашего сценария (если вы говорите о еженедельном списке задач, вам, вероятно, нужно обновлять его каждые 5 минут или около того. Если вы говорите список задач в течение следующих 30 минут, вам может потребоваться обновляйте его каждую минуту или 30 секунд или что-то в этом роде.

Этот метод позволит избежать проблем, упомянутых вами с опцией обновления, поскольку будут затронуты только привязки TimeLeft. Если бы у вас было миллионы таких задач, думаю, снижение производительности было бы довольно значительным. Но если бы у вас было всего несколько десятков или около того, обновление этих привязок каждые 30 секунд или около того было бы довольно незначительной проблемой, верно?

Каждая возможность, о которой я могу думать, использует либо Таймеры, либо Анимации. Анимации будут слишком «тяжелыми», когда вы добавляете задачи в список. Что касается сценариев с таймером, то вышеприведенный сценарий кажется наиболее чистым, простым и практичным. Вероятно, просто сводится к тому, работает ли это или нет для вашего конкретного сценария.

1 голос
/ 29 сентября 2011

Я прочитал ваш принятый ответ, но мне было просто интересно ... почему бы просто не отключить привязки для этой конкретной задачи в режиме «Редактирование», чтобы вас не прерывали?Затем просто включите эту привязку, когда закончите, или отмените редактирование?Таким образом, даже если ваш таймер обновляется каждую секунду, кого это волнует?

Что касается того, как отключить их, не отключая их (и, следовательно, не сбрасывая их значение), просто определите логический флаг, а затем во всех DP, которые вы хотитечтобы прервать, проверьте этот флаг в логике проверки.Если флаг имеет значение true, и объект DependencyObject, к которому он применяется, является тем, который вы редактируете, заблокируйте изменение в DP.

В любом случае, это просто появилось в моей голове.На самом деле это не проверялось, но это должно быть легко.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...