14

OK, więc tutaj jest problem: napisałem UserControl, który odbiera nową wartość, powiedzmy co każde 100ms i coś z nią robimy. Musi obsłużyć każdy nowy ustawnik wartości, nawet jeśli jego wartość się nie zmieniła. UserControl ma kilka DependencyProperties:DependencyProperty nie uruchamia ValueChanged, gdy nowa wartość jest taka sama

public double CurrentValue 
    { 
     get { return (double)GetValue(CurrentValueProperty); } 
     set { SetValue(CurrentValueProperty, value); } 
    } 

    public static readonly DependencyProperty CurrentValueProperty = 
     DependencyProperty.Register("CurrentValue", typeof(double), typeof(GraphControl), new UIPropertyMetadata(0d)); 

W XAML gdzie służy ta kontrola, po prostu ustawić Binding z CurrentValue do (INotifyPropertyChanged obsługującym) nieruchomości:

<uc:UserControl CurrentValue="{Binding MyValue}" ... /> 

ViewModel:

public double MyValue 
    { 
     get { return _value; } 
     set 
     { 
      //if (_value == value) return; 
      _value= value; 
      if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs("MyValue")); 
     } 
    } 

Jak widać, jednoznacznie skomentowałem if equals then return, aby wywołać zdarzenie PropertyChanged, nawet gdy wartość zostanie zaktualizowana na taką samą wartość.

Powróciłem do kontroli użytkownika, próbowałem zarejestrować ValueChanged na dwa sposoby; najpierw za pomocą DependencyPropertyDescriptor:

var propertyDescriptor = DependencyPropertyDescriptor.FromProperty(CurrentValueProperty, typeof(GraphControl)); 
propertyDescriptor.AddValueChanged(this, OnCurrentValueChanged); 

lub za pomocą UIPropertyMetaData:

new UIPropertyMetadata(0d, OnCurrentValueChangedCallback) 

więc stub zwrotnego wyglądałby następująco:

private void Callback(object sender, EventArgs e){ 
    //do stuff 
} 

Ok teraz problem to, że wywołanie zwrotne nie jest wywoływane, gdy wartość nie zmienia się jawnie. Sprawdziłem i wydarzenie PropertyChanged wystrzeliło w moim modelu widoku, ale sterowanie nie widzi zmiany. Gdy wartość zmieni się na nową wartość, obsłuży wywołanie zwrotne zgodnie z oczekiwaniami.
Czy istnieje sposób na zastąpienie tego zachowania, aby moja metoda wywołania zwrotnego zawsze była trafiona?

EDIT:
Próbowałem też za pomocą CoerceValueCallback, a jeden jest trafiony, gdy wartość pozostaje taka sama, ale nie mi pomóc z moim problemem myślę ...

Odpowiedz

4

Można zawiń wartość w obiekcie, tj. utwórz klasę do jej przechowywania - następnie za każdym razem ustaw właściwość na nowe wystąpienie tej klasy zawierające nową wartość. Oznacza to, że tworzysz ~ 10 obiektów na sekundę, ale każdy z nich jest inny, wywoła zdarzenie zmiany i jest tylko mały (i tak będzie GC). :)

+0

Aaaaaaaaaaaaaaaaaaaaaaaaaa, dlaczego nie pomyślałam o tym! :-) Działa idealnie, dziękuję! – RoelF

0

Inną alternatywą jest chwilowe przestawienie wartości na coś innego, a następnie przywrócenie poprzedniej. Można zrobić całą tę sprawę w sposób przejrzysty zwrotnego przymusić jako takie:

public static readonly DependencyProperty TestProperty = DependencyProperty.Register(
    "Test", typeof(object), typeof(School), 
    new PropertyMetadata(null, TestChangedCallback, TestCoerceCallback)); 

static object TestCoerceCallback(DependencyObject d, object baseValue) 
{ 
    if (baseValue != null && (d.GetValue(TestProperty) == baseValue)) 
    { 
     d.SetCurrentValue(TestProperty, null); 
     d.SetCurrentValue(TestProperty, baseValue); 
    } 
    return baseValue; 
} 

Wystarczy upewnić się, że kod nieruchomość może obsłużyć sprawę null wartość wdziękiem.

Powiązane problemy