【问题标题】:DataTrigger not reevaluating after property changes属性更改后 DataTrigger 未重新评估
【发布时间】:2023-03-31 23:55:02
【问题描述】:

[原创]
我有一个ListBox,它的ItemsSource(这是在创建窗口时在后面的代码中完成的)数据绑定到ObservableCollection。然后ListBox 会针对这些项目分配以下DataTemplate:

用户控件.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]
继 Timores 制造的 cmets 之后,我尝试了以下方法:

用户控件.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,但“未接听”保持不变。如果我关闭窗口,然后再次重新打开它(活动调用仍将属性 hasBeenAnswered 设置为 true),则背景为蓝色。所以在我看来,数据触发器根本没有运行,直到窗口重新运行。

【问题讨论】:

    标签: wpf datatemplate datatrigger


    【解决方案1】:

    在示例中我觉得奇怪的是,您使用的是 ItemContainerStyle 而不是 ItemTemplate。

    ItemContainerStyle 适用于包含 ItemsSource 中每个元素的 ListBoxItem。 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 的​​属性名称中的最小错误可以解释您的行为。触发器可能基于正确的属性,但通知的名称可能拼写错误。

    【讨论】:

    • 我已经尝试实现这一点,但它仍然只适用于我关闭窗口并重新打开它的情况。我将修改初始评论以显示这一点。你有什么想法吗?
    • 啊啊啊啊!我明白了,我自己的愚蠢拼写,你是对的,在 INotifyProperyChanged 中我有“hasBeenAsnwered”而不是“hasBeenAnswered”。私人布尔_hasBeenAnswered;公共布尔 hasBeenAnswered { 获取 { 返回 _hasBeenAnswered; } 设置 { _hasBeenAnswered = 值; NotifyPropertyChanged("hasBeenAnswered"); } } } 感谢您的帮助。
    • 不客气。但我原来是错的,即ItemContainerStyle中的DataContext确实是里面的item,而不是ListBoxItem。我将示例更改为更像您的原始问题,并且它也有效。
    猜你喜欢
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    相关资源
    最近更新 更多