/ / DataTrigger nie dokonuje ponownej oceny po zmianie właściwości - wpf, datatemplate, datatrigger

DataTrigger nie dokonuje ponownej oceny po zmianach właściwości - wpf, datatemplate, datatrigger

[Oryginał]
mam ListBox który ma swoje ItemsSource (odbywa się to w kodzie z tyłu, gdy tworzone jest okno) databound to an ObservableCollection. The ListBox następnie ma następujące DataTemplate przypisane do pozycji:

usercontrol.xaml

<ListBox x:Name="communicatorListPhoneControls"
ItemContainerStyle="{StaticResource templateForCalls}"/>

app.xaml

<Style x:Key="templateForCalls" TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate" Value="{StaticResource templateRinging}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=hasBeenAnswered}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource templateAnswered}"/>
</DataTrigger>
</Style.Triggers>
</Setter>
</Style>

Kiedy ObservableCollection jest aktualizowany o obiekt, pojawia się w ListBox z poprawną inicjałem DataTemplate, jednak gdy hasBeenAnswered Właściwość jest ustawiona na true (podczas debugowania widzę, że kolekcja jest poprawna) DataTrigger nie dokonuje ponownej oceny, a następnie aktualizuje ListBox użyć poprawnego DataTemplate.

Zaimplementowałam INotifyPropertyChanged Zdarzenie w moim obiekcie i jeśli szablon jest powiązany z wartością, widzę aktualizację wartości. Po prostu DataTrigger nie będzie ponownie oceniać i zmieniać na właściwy szablon.

Wiem, że DataTrigger powiązanie jest poprawne, ponieważ jeśli zamknę okno i otworzę je ponownie, poprawnie zastosuje drugą tabliczkę danych, ponieważ plik hasBeenAnswered jest ustawione na true.

[edytuj 1]
W związku z komentarzami Timora wypróbowałem następujące rozwiązania:

usercontrol.xaml

<ListBox x:Name="communicatorListPhoneControls"
ItemTemplate="{StaticResource communicatorCallTemplate}"/>`

app.xaml:

<DataTemplate x:Key="communicatorCallTemplate">
<Label x:Name="test">Not answered</Label>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=hasBeenAnswered}" Value="True">
<Setter TargetName="test" Property="Background" Value="Blue"/>
</DataTrigger>
</DataTemplate.Triggers>
</Label>
</DataTemplate>

To, co dzieje się teraz, jest podobne do pierwszego przykładu,kiedy nadejdzie połączenie, wyświetla się etykieta „Nie odebrano” (jedno na połączenie, które istnieje, ponieważ jest to lista - zwykle po załadowaniu okna nie będzie żadnych połączeń), połączenie jest następnie odbierane, a właściwość hasBeenAnswered ma wartość prawda, ale „Brak odpowiedzi” pozostajeto samo. Jeśli zamknę okno i ponownie je otworzę (z aktywnym połączeniem nadal z właściwością hasBeenAnsrated ustawioną na true) tło jest wtedy niebieskie. Więc wydaje mi się, że datatrigger po prostu nie jest uruchamiany, dopóki okno nie zostanie ponownie uruchomione.

Odpowiedzi:

1 dla odpowiedzi № 1

W tym przykładzie wydaje mi się dziwne, że używasz ItemContainerStyle zamiast ItemTemplate.

ItemContainerStyle ma zastosowanie do ListBoxItem, który zawiera każdy element w ItemsSource. ListboxItem nie ma pliku hasBeenAnswered własności, więc nie wiem, jak to wiązanie mogłoby działać.

Proponuję utworzyć DataTemplate dla typu danych w polu listy i użyć wyzwalaczy, aby wprowadzić takie same zmiany, jak w templateAnswered styl.

Edycja: po tym, jak OP skorzystał z sugestii ItemTemplate.

Próbowałem odtworzyć przykład i u mnie działa dobrze. Oto mój kod XAML (proszę zignorować styl, to tylko przykład):

Bez odpowiedzi

    <ListBox x:Name="communicatorListPhoneControls"
ItemTemplate="{StaticResource communicatorCallTemplate}"/>

<Button Margin="0,20,0,0" Click="OnToggleAnswer" Content="Toggle answer status" />
</StackPanel>

A w kodzie:

public partial class Window1 : Window {

public Window1() {
InitializeComponent();

List<PhoneCall> lpc = new List<PhoneCall>()
{new PhoneCall(), new PhoneCall(), new PhoneCall(), new PhoneCall()};

communicatorListPhoneControls.ItemsSource = lpc;
}

private void OnToggleAnswer(object sender, RoutedEventArgs e) {

object o = communicatorListPhoneControls.SelectedItem;

if (o != null) {

PhoneCall pc = (PhoneCall) o;
pc.hasBeenAnswered = ! pc.hasBeenAnswered;
}
}
}

public class PhoneCall : INotifyPropertyChanged {

private bool _answered;


public bool hasBeenAnswered {
get { return _answered;  }
set {
if (_answered != value) {
_answered = value;
FirePropertyChanged("hasBeenAnswered");
}
}
}

private void FirePropertyChanged(string propName) {

if (PropertyChanged != null) {

PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

Czy mógłbyś spróbować to odtworzyć i porównać zTwój kod ? Uwaga: najmniejszy błąd w nazwie właściwości nadanej PropertyChanged może wyjaśnić twoje zachowanie. Wyzwalacz może być oparty na właściwej właściwości, ale powiadomienie może mieć błędnie zapisaną nazwę.