Swapper
Swapper

Reputation: 107

WPF DataTrigger is false but doesn't revert to previous value

I recently created a user control which informs a user about how many notifications he has. Since I wanted this user control to only show itself if there are any notifications I created a DataTrigger which binds to a bool and sets the visibility to collapsed when there are no notifications. It works fine in the beginning and my user control is collapsed but during my program I add a notification and call NotifyPropertyChanged on my bool but the user control still stays hidden for some unknown reason.

User Control

<UserControl.Style>
    <Style TargetType="{x:Type UserControl}">
        <Setter Property="Visibility"
                    Value="Visible">
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding HasNotifications}"
                             Value="False">
                <Setter Property="Visibility"
                            Value="Collapsed">
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Style>

DataContext

private ObservableCollection<Notification> notifications;
public ObservableCollection<Notification> Notifications
{
    get { return notifications; }
}

public bool HasNotifications
{
    get
    {
        return Notifications.Count > 0;
    }
}

public void AddNotification(Notification notificationToAdd)
{
    notifications.Add(notificationToAdd);
    NotifyPropertyChanged(nameof(Notifications));
    NotifyPropertyChanged(nameof(HasNotifications));
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void NotifyPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

I also tried to put a DataTrigger with the opposite value (set visibility to on when HasNotifications is true) but it also didn't work out for me.

Upvotes: 1

Views: 746

Answers (1)

Arie
Arie

Reputation: 5373

I copied your code and tested it under 3.5 and 4.7 frameworks, and it works. I was able to reproduce your issue in only one case, but I'm guessing here since that part isn't in your code sample.

It doesn't work only if the data context class doesn't inherit from INotifyPropertyChanged. Otherwise the minimal code sample works as expected.

public class MyDataContext :  INotifyPropertyChanged // <= doesn't work if this is missing
{
    private ObservableCollection<Notification> notifications = new ObservableCollection<Notification>();
    public ObservableCollection<Notification> Notifications => notifications;

    public bool HasNotifications=> Notifications.Count > 0;

    public void AddNotification(Notification notificationToAdd)
    {
        notifications.Add(notificationToAdd);
        NotifyPropertyChanged(nameof(Notifications));
        NotifyPropertyChanged(nameof(HasNotifications));
    }

    private ICommand _AddNotification;
    public ICommand AddNotificationCMD => _AddNotification ?? (_AddNotification = new RelayCommand<object>(a => AddNotificationCommand(a)));

    private void AddNotificationCommand(object item)
    {
        AddNotification(new Notification());
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

<Window x:Class="WpfApp_3_5_framework_test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp_3_5_framework_test"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <local:UserControl1/>
    <Button Content="Add Notification" Command="{Binding AddNotificationCMD}" Height="20" Width="200" />
</Grid>
</Window>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MyDataContext();
    }
}

<UserControl x:Class="WpfApp_3_5_framework_test.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfApp_3_5_framework_test"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Style>
    <Style TargetType="{x:Type UserControl}">
        <Setter Property="Visibility"
                Value="Visible">
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="{Binding HasNotifications}"
                         Value="False">
                <Setter Property="Visibility"
                        Value="Collapsed">
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Style>
<Grid>
    <StackPanel>
        <Border Width="100" Height="100" Background="Red"/>
    </StackPanel>
</Grid>
</UserControl>

Upvotes: 2

Related Questions