[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 № 1W 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ę.