I have a simple C# WPF application looking like this:
I'm adding Item2 programmatically, and I wonder why the Loaded
event is fired both shortly after it has been added to the TabControl
and then again when I open it.
The code for my MainWindow.xaml
looks as follows:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl Name="MyTabControl" >
<TabItem Name="Item1" Header="Item1">
<local:Control1 />
</TabItem>
</TabControl>
</Grid>
</Window>
And its code-behind is:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var item = new TabItem
{
Content = new Control2(),
Header = "Item2"
};
MyTabControl.Items.Add(item);
}
}
}
As you can see, I have one control called Control1
and another called Control2
. They are defined with the following MyControl.xaml
file:
<UserControl x:Class="WpfApplication1.MyControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
</Grid>
</UserControl>
And the following code-behind MyControl.xaml.cs
:
using System.Diagnostics;
namespace WpfApplication1
{
public abstract partial class MyControl
{
protected abstract string MyName { get; }
protected MyControl()
{
InitializeComponent();
Loaded += (sender, args) => Debug.Print("Loaded {0}", MyName);
Unloaded += (sender, args) => Debug.Print("Unloaded {0}", MyName);
}
}
public class Control1 : MyControl
{
protected override string MyName => "Control1";
}
public class Control2 : MyControl
{
protected override string MyName => "Control2";
}
}
When I open the application, I get the following console output:
Loaded Control1
Loaded Control2
And when I switch to Item2:
Unloaded Control1
Loaded Control2
And back to Item1:
Unloaded Control2
Loaded Control1
The latter two make sense; when I navigate from a control it gets unloaded while the new control gets loaded.
However, I don't understand why Control2 is loaded initially, before it has been shown. This causes Control2 to receive two Loaded
events in a row, before it gets an Unloaded
event.