I have an ItemsControl
inside a Popup
with an ObservableCollection
, which I'll refer to as simply 'Collection', bound to the ItemsControl.ItemsSource
property.
The ItemsControl
will always duplicate the first item added to the Collection. The ItemsControl
then behaves correctly for every item added thereafter.
ItemsControl.ItemsPanel
is a StackPanel
with no virtualization.I found a similar question. However, the proposed solution did not solve my issue.
I have a hunch that is due to using the ItemsControl
inside a Popup
but I can't figure out why this is happening, and only with the first item.
Any suggestions?
EDIT:
The Collection is updated in a separate singleton class. On Initialization of my View & ViewModel I create a local Collection referencing the one within the singleton. I can confirm that there are no duplicate items added to the Collection and that it does behave correctly.
Here is some sample code:
XAML:
<Popup IsOpen="{Binding ShowNotifications, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
StaysOpen="True"
AllowsTransparency="True">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemsSource="{Binding AlarmNotifications}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Exception.Message}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Popup>
C# View-Model:
public ManagerClass Manager { get; set; }
public ObservableCollection<AlarmRegistry> AlarmNotifications { get; set; }
public bool ShowAlarmNotifications => AlarmNotifications.Any();
protected MainViewModel()
{
Manager = ManagerClass.Instance;
AlarmNotifications = Manager.AlarmNotifications;
AlarmNotifications.CollectionChanged += (sender, args) =>
{
OnPropertyChanged(nameof(ShowAlarmNotifications));
};
}
UPDATE:
I found two approaches which correct the duplication which involve opening the Popup before the first item is added:
Popup.IsOpen
binding and setting it to true in XAML.ShowNotifications
to true.These approaches cause the application to start with the Popup open, which is an undesired behavior. However, this stops the ItemsControl duplicating the first item added. If the Popup is closed again before the first item is added, the duplication does not occur.
Now I am searching for a way to keep the Popup closed at start-up without having the first item duplicated. One approach would be trying to trick the Popup into opening and closing immediately after.
If you know why this happens, or how to counter it, please let me know.
The duplication occurs if the Popup is not opened before the first item is added to the collection.
In order to correct the issue there were three steps:
Add a setter and to the ShowAlarmNotifications
property so it may be set directly and update the usages:
private bool _showAlarmNotifications;
public bool ShowAlarmNotifications
{
get => _showAlarmNotifications;
set
{
_showAlarmNotifications = value;
OnPropertyChanged();
}
}
AlarmNotifications.CollectionChanged += (sender, args) =>
{
ShowAlarmNotifications = AlarmNotifications.Any();
};
Create a Loaded
event for the View and set ShowAlarmNotifications
to true
:
private void View_OnLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModel vm)
vm.ShowAlarmNotifications = true;
}
Create a Loaded
event for the Popup and set ShowAlarmNotifications
to false
:
private void Popup_OnLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModel vm)
vm.ShowAlarmNotifications = false;
}
The ItemsControl
no longer duplicates the first entry and the Popup
is not open when the application starts up.
This is a messy solution and still doesn't explain why the duplication happens but it does satisfy the requirements.