2010-03-12 14 views
5

[Original]
Tengo un ListBox que tiene su ItemsSource (esto se hace en el código detrás de como se crea la ventana) de enlace de datos a un ObservableCollection. El ListBox tiene entonces la siguiente DataTemplate asignado en contra de los artículos:DataTrigger no volver a evaluar después de la propiedad cambia

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> 

Cuando el ObservableCollection se actualiza con un objeto, éste aparece en la ListBox con la inicial correcta DataTemplate, sin embargo, cuando la propiedad hasBeenAnswered se establece en true (cuando la depuración puedo ver la colección es correcta) el DataTrigger no vuelve a evaluar y luego actualiza el ListBox para usar el DataTemplate correcto.

He implementado el evento INotifyPropertyChanged en mi objeto, y si en la plantilla está vinculado a un valor, puedo ver la actualización del valor. Es solo que el DataTrigger no volverá a evaluar y cambiar a la plantilla correcta.

sé la unión DataTrigger es correcto porque si cierro la ventana y la abro de nuevo, correctamente se aplicará la segunda DataTemplate, debido a que el hasBeenAnswered se establece en true.

[editar 1]
A raíz de los comentarios realizados por Timores He intentado lo siguiente:

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> 

Lo que sucede ahora es similar al primer ejemplo, cuando aparece una llamada en la etiqueta "No contestado" (uno por llamada que existe ya que este es un cuadro de lista, normalmente cuando la ventana se carga no habrá llamadas), la llamada se responde y el valor hasBeenAnswered se establece en verdadero, pero el "Sin respuesta" sigue siendo el mismo. Si cierro la ventana y la vuelvo a abrir (con la llamada activa aún con la propiedad hasBeenAnswered establecida en verdadero), el fondo es azul. Entonces me parece que el datatrigger simplemente no se está ejecutando, hasta que se vuelva a ejecutar la ventana.

Respuesta

1

Lo que me parece extraño en el ejemplo es que está utilizando un ItemContainerStyle en lugar de una ItemTemplate.

ItemContainerStyle se aplica al ListBoxItem que contiene cada elemento en su ItemsSource. ListboxItem no tiene una propiedad hasBeenAnswered, por lo que no veo cómo podría funcionar el enlace.

Sugiero crear un DataTemplate para el tipo de datos en su cuadro de lista y usar disparadores para hacer los mismos cambios que en su estilo templateAnswered.

Editar: después de que OP utilizara la sugerencia de ItemTemplate.

He intentado reproducir el ejemplo, y funciona bien para mí. Aquí es mi XAML (no tenga en cuenta el estilo, esto es sólo un ejemplo):

no contestadas

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

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

Y en el código- detrás:

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; 
} 

¿Podría intentar reproducir esto y compararlo con su código? Nota: el error más pequeño en el nombre de propiedad dado a PropertyChanged podría explicar su comportamiento. El activador podría basarse en la propiedad correcta, pero la notificación podría tener un nombre mal escrito.

+0

He intentado implementar esto, pero aún se aplica solo si cierro la ventana y la vuelvo a abrir. Voy a enmendar el comentario inicial para mostrar esto. ¿Tienes alguna idea? –

+0

AHHHHH! Lo tengo, mi propia ortografía estúpida, estabas en lo cierto, en el INotifyProperyChanged tuve "hasBeenAsnwered" en lugar de "hasBeenAnswered". private Boolean _hasBeenAnswered; public Boolean hasBeenAnswered { get {return _hasBeenAnswered; } conjunto { _hasBeenAnswered = value; NotifyPropertyChanged ("hasBeenAnswered"); } } } gracias por toda su ayuda. –

+0

De nada. Pero me equivoqué originalmente, es decir, el DataContext en ItemContainerStyle es realmente el elemento dentro, no el ListBoxItem. Cambié mi ejemplo para que se parezca más a tu pregunta original, y también funciona. – Timores

Cuestiones relacionadas