DataTrigger не переоценивает после изменения свойства - PullRequest
5 голосов
/ 12 марта 2010

[оригинал]
У меня есть ListBox, у которого есть ItemsSource (это делается в коде позади при создании окна) с привязкой к ObservableCollection. ListBox затем присваивается следующее значение DataTemplate для элементов:

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>

Когда ObservableCollection обновляется объектом, он появляется в ListBox с правильным начальным DataTemplate, однако, когда для свойства hasBeenAnswered установлено значение true (при отладке я вижу коллекцию правильно) DataTrigger не переоценивает, а затем обновляет ListBox для использования правильного DataTemplate.

Я реализовал INotifyPropertyChanged Событие в моем объекте, и если в шаблоне привязано значение, я могу увидеть обновление значения. Просто DataTrigger не будет переоценивать и менять правильный шаблон.

Я знаю, что привязка DataTrigger правильная, потому что, если я закрою окно и открою его снова, он будет правильно применять вторую таблицу данных, потому что hasBeenAnswered установлен на true.

[править 1]
Следуя комментариям Тимора, я попробовал следующее:

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>

То, что происходит сейчас, аналогично первому примеру, когда вызов поступает в метке «Не ответил» (по одному на вызов, который существует, так как это список - обычно, когда окно загружается, вызовов не будет), Затем на вызов поступает ответ, и для пророчества hasBeenAnswered устанавливается значение true, но «Не отвеченный» остается тем же. Если я закрою окно и снова открою его (при активном вызове, для которого свойство hasBeenAnspted имеет значение true), фон будет синим. Поэтому мне кажется, что сборщик данных просто не запускается, пока окно не будет перезапущено.

1 Ответ

1 голос
/ 12 марта 2010

В данном примере мне кажется странным, что вы используете ItemContainerStyle вместо ItemTemplate.

ItemContainerStyle применяется к ListBoxItem, который содержит каждый элемент в вашем ItemsSource. ListboxItem не имеет свойства hasBeenAnswered, поэтому я не вижу, как может работать привязка.

Я предлагаю создать DataTemplate для типа данных в списке и использовать триггеры для внесения тех же изменений, что и в вашем стиле templateAnswered.

Редактировать: после того, как OP использовал предложение ItemTemplate.

Я попытался воспроизвести пример, и он отлично работает для меня. Вот мой XAML (не обращайте внимания на стиль, это всего лишь пример):

Не отвечено

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

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

А в коде позади:

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

Не могли бы вы попытаться воспроизвести это и сравнить с вашим кодом? Примечание: наименьшая ошибка в имени свойства, переданного PropertyChanged, может объяснить ваше поведение. Триггер может основываться на правильном свойстве, но в уведомлении может быть указано имя с ошибкой.

...