2009-03-19 14 views
9

Próbuję zmierzyć obiekt natychmiast po zmianie DataContext, ale powiązanie obiektu nie zostanie wkrótce zaktualizowane. Oto mój kod:Aktualizowanie powiązania natychmiast po zmianie 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); 
} 

Chcę powiązań na widok obiektu do aktualizacji, aby można było mierzyć jak duża musi być widok, aby wyświetlić ViewModel. Używam tego samego widoku do pomiaru, ponieważ dokonuję wirtualizacji danych.

Czy ktoś wie, jak wymusić powiązanie, aby zaktualizować po zmianie DataContext?

Należy pamiętać, że powiązanie aktualizuje się ostatecznie.

Widok zawiera element TextBlock, który jest głównym elementem zmieniającym rozmiar na podstawie modelu ViewModel. Spojrzałem na BindingExpression dla TextProperty na tym elemencie natychmiast po zmianie DataContext, ale wywołanie UpdateTarget() nie rozwiązuje problemu i BindingExpression.DataItem wydaje się mieć wartość NULL.

EDYTOWANIE: Status wartości BindingExression nie jest przyłączony. Sztuką jest dowiedzieć się, jak to dołączyć.

Odpowiedz

5

Cóż, jeśli po ustawieniu DataContext wykonałeś Invoke na Dispatcherze w priorytecie DataBind, powinno to spowodować, że wszystkie zostaną zaktualizowane.

Ponieważ ten kod jest wykonywany wewnątrz metody MeasureOverride, nie można wykonać Invoke na Dispatcherze. Zamiast tego utworzyłbym flagę wskazującą, czy szerokość linijki została zmierzona, a jeśli nie, wykonaj BeginInvoke w metodzie, która oblicza te szerokości. Następnie, gdy szerokości są obliczane, wywołaj InvalidateMeasure, aby wymusić drugie przejście układu.

Będzie to wymagać dodatkowego przełożenia układu za każdym razem, gdy zmieni się jedna z tych szerokości. Będziesz musiał zresetować flagę do wartości false, gdy tylko pola będą musiały zostać ponownie odfiltrowane.

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(); 
} 
+0

Dobry pomysł. Spróbuję tego. –

+0

Mam następujący wyjątek: Nie można wykonać tej operacji, gdy przetwarzanie programu rozsyłającego jest zawieszone. Wygląda na to, że WPF blokuje Dispatcher podczas układania. Uruchamiam ten kod w MeasureOverride() –

Powiązane problemy