Обновление Binding немедленно при изменении DataContext - PullRequest
9 голосов
/ 19 марта 2009

Я пытаюсь измерить объект сразу после изменения DataContext, но привязка для объекта не обновляется достаточно скоро. Вот мой код:

// In MeasureOverride(Size)
m_inputWidth = 0.0;

Size elemSize = new Size(double.PositiveInfinity, RowHeight);
MapElementView ruler = new MapElementView();

// Measure inputs
foreach (MapElementViewModel elem in m_vm.InputElements)
{
   ruler.DataContext = elem;
   ruler.Measure(elemSize);
   m_inputWidth = Math.Max(m_inputWidth, ruler.DesiredSize.Width);
}

Я хочу обновить привязки для объекта View, чтобы я мог измерить, насколько большим должно быть представление для отображения ViewModel. Я повторно использую тот же вид для измерения, потому что я виртуализирую данные.

Кто-нибудь знает, как принудительно обновить привязку при изменении DataContext?

Обратите внимание, что привязка со временем обновляется.

Представление содержит TextBlock, который является основным элементом, который изменяет размер на основе ViewModel. Я посмотрел на BindingExpression для TextProperty для этого элемента сразу после изменения DataContext, но вызов UpdateTarget () не решает проблему, и BindingExpression.DataItem представляется равным нулю.

EDIT: Статус BindingExression является Unattached. Хитрость заключается в том, чтобы выяснить, как его прикрепить.

1 Ответ

5 голосов
/ 21 марта 2009

Хорошо, если после установки DataContext вы выполнили Invoke для Dispatcher с приоритетом DataBind, это должно привести к их обновлению.

Поскольку этот код выполняется внутри метода MeasureOverride, вы не можете выполнить Invoke для Dispatcher. Вместо этого я бы сделал флажок, который бы указывал, была ли измерена ширина линейки, а если нет, выполните BeginInvoke для метода, который вычисляет эту ширину. Затем, когда ширина будет рассчитана, вызовите InvalidateMeasure, чтобы вызвать второй проход макета.

Для этого потребуется дополнительный проход макета каждый раз, когда изменяется одна из этих значений ширины. Вам нужно будет сбросить флажок на «ложь» всякий раз, когда необходимо повторно измерить текстовые поля.

private bool isRulerWidthValid = false;

protected override Size MeasureOverride(Size available)
{
    ... // other code for measuring
    if (!isRulerWidthValid)
    { 
        Dispatcher.BeginInvoke(new Action(CalculateRulerSize));
        ... // return some temporary value here
    }

    ... // do your normal measure logic
}

private void CalculateRulerSize(Size available)
{
    Size elemSize = new Size(double.PositiveInfinity, RowHeight);
    m_inputWidth = 0.0;

    foreach (MapElementViewModel elem in m_vm.InputElements)
    {
       ruler.DataContext = elem;
       ruler.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.DataBind);
       ruler.Measure(elemSize);
       m_inputWidth = Math.Max(m_inputWidth, ruler.DesiredSize.Width);
    }

    // invalidate measure again, as we now have a value for m_inputwidth
    isRulerWidthValid = true;
    InvalidateMeasure();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...