Сначала вы устанавливаете AddPlayer.DataContext
на неинициализированное свойство Player
внутри конструктора AddPlayer
:
public AddPlayer(Player player)
{
DataContext = Player; // Wrong! Property is not initialized.
InitializeComponent(); // Wrong! InitializeComponent() should be the very first call
Player = player;
}
Это может быть опечатка. Кроме того, InitializeComponent()
всегда должен быть самым первым вызовом.
Но после создания AddPlayer
вы переопределяете сам DataContext by setting it to the
AddPlayer`:
public void AddTabItem(String name, UserControl userControl)
{
TabItem tab = new TabItem
{
Header = name
};
userControl.DataContext = userControl; // Wrong! This overrides the constructor assignment.
tab.Content = userControl;
TabControl.Items.Add(tab);
}
Вместо этого добавляйте элементы в TabControl.ItemsSource
и позвольте элементу управления обрабатывать DataContext
. Также никогда не применяйте INotifyPropertyChanged
в элементах управления (или DependencyObject
. Всегда реализуйте DependencyProperty
, так как это имеет гораздо лучшую производительность. Также очень вероятно, что свойства элемента управления - Binding.Target
и привязаны к источнику данных. Binding.Target
должен быть DependencyProperty
:
TabItemData.cs
public class TabItemData
{
public TabItemData(string title, Player player)
{
this.Title = title;
this.Player = player;
}
public Player Player { get; set; }
public string Title { get; set; }
}
AddPlayer.xaml.cs
public partial class AddPlayer : UserControl, INotifyPropertyChanged
{
public AddPlayer()
{
InitializeComponent();
// Player is already the DataContext, set from XAML DataTemplate.
// Access player like "var player = this.DataContext as Player;"
// This instance is automatically created by a DataTemplate
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static readonly DependencyProperty PlayersProperty = DependencyProperty.Register(
"Players",
typeof(ObservableCollection<TabItemData>),
typeof(MainWindow),
new PropertyMetadata(default(ObservableCollection<TabItemData>)));
public ObservableCollection<TabItemData> Players
{
get => (ObservableCollection<TabItemData>) GetValue(MainWindow.PlayersProperty);
set => SetValue(MainWindow.PlayersProperty, value);
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.Players = new ObservableCollection<TabItemData>();
}
private void AddPlayerClick(Object sender, RoutedEventArgs e)
{
this.Players.Add(new TabItemData("New Player", new Player(1, "asd", "asd", new DateTime(1,2,3), "asd", "asd", "asd", "asd", true)));
}
}
MainWiindow.xaml
<Window x:Name="Window">
<StackPanel>
<Menu>
<MenuItem Header="Players">
<MenuItem Header="Add Player" Click="AddPlayerClick" />
</MenuItem>
</Menu>
<TabControl ItemsSource="{Binding ElementName=Window, Path=Players>
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type TabItemData}">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type TabItemData}">
<AddPlayer DataContext="{Binding Player}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</Window>