Reputation: 1457
I'm trying to add a new TabItem
to TabControl
each time I click on a button and I have no problem with that. But I want a textbox inside each TabItem
. How do I do that? I need to do that with code I suppose.
TabItem newTab = new TabItem();
newTab.Header = ncn.courseName;
newTab.FontSize = 20;
TextBox textbox = new TextBox();
textbox.Width = 200;
textbox.Height = 100;
textbox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
textbox.VerticalAlignment = System.Windows.VerticalAlignment.Top;
Grid grid = new Grid();
grid.Children.Add(textbox);
newTab.Content = grid;
this.Courses.Items.Add(newTab);
this.Courses.SelectedItem = newTab;
Upvotes: 1
Views: 12592
Reputation: 1405
If you would like to use only code and not the MVVM pattern, this can be solved this way:
private void button1_Click(object sender, RoutedEventArgs e)
{
TabItem item = null;
Grid grid = null;
TextBox textbox = null;
try
{
// Creating the TextBox
textbox = new TextBox();
textbox.Width = 200;
textbox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
textbox.VerticalAlignment = System.Windows.VerticalAlignment.Top;
// Creating the Grid (create Canvas or StackPanel or other panel here)
grid = new Grid();
grid.Children.Add(textbox); // Add more controls
item = new TabItem();
item.Header = "Hello, this is the new tab item!";
item.Content = grid; // OR : Add a UserControl containing all controls you like, OR use a ContentTemplate
MyTabControl.Items.Add(item);
MyTabControl.SelectedItem = item; // Setting focus to the new TabItem
}
catch (Exception ex)
{
MessageBox.Show("Error creating the TabItem content! " + ex.Message);
}
finally
{
textbox = null;
grid = null;
item = null;
}
}
That is solving it "the old way" by using code-behind.
If you on the other want to use the WPF like it should, you can do like this. To simplify a bit, I am using the code-behind as DataContext. I would recommend using a class instead in the running code. I have also used the Cutton click event instead if using the Button Command.
First I create a "holder" class for the tab items, holding the data you need.
TabItemHolder.cs
public class TabItemHolder : DependencyObject, INotifyPropertyChanged
{
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(String), typeof(TabItemHolder), new UIPropertyMetadata());
public String Header
{
get { return (String)GetValue(HeaderProperty); }
set
{
SetValue(HeaderProperty, value);
NotifyPropertyChanged("Header");
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(String), typeof(TabItemHolder), new UIPropertyMetadata());
public String Text
{
get { return (String)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
NotifyPropertyChanged("Text");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
Then I have the model class, in this example the MainWindow.cs itself:
MainWindow.cs
public partial class MainWindow : Window, INotifyPropertyChanged { public static readonly DependencyProperty SelectedTabProperty = DependencyProperty.Register("SelectedTab", typeof(TabItemHolder), typeof(MainWindow), new UIPropertyMetadata()); public TabItemHolder SelectedTab { get { return (TabItemHolder)GetValue(SelectedTabProperty); } set { SetValue(SelectedTabProperty, value); NotifyPropertyChanged("SelectedTab"); } }
public static readonly DependencyProperty TabsProperty = DependencyProperty.Register("Tabs", typeof(ObservableCollection<TabItemHolder>), typeof(MainWindow), new UIPropertyMetadata());
public ObservableCollection<TabItemHolder> Tabs
{
get { return (ObservableCollection<TabItemHolder>)GetValue(TabsProperty); }
set
{
SetValue(TabsProperty, value);
NotifyPropertyChanged("Tabs");
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.Tabs = new ObservableCollection<TabItemHolder>();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this.Tabs.Add(new TabItemHolder() { Header = "Hello, this is the new tab item!", Text = "Dummy text for the textbox" });
this.SelectedTab = this.Tabs[this.Tabs.Count - 1];
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
And finally, the XAML would be something like this.
MainWindow.xaml
<Grid x:Name="LayoutRoot">
<TabControl x:Name="MyTabControl"
Margin="12,67,12,12"
ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTab}">
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<TextBox Text="{Binding Path=Text}"
Width="200"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
<Button Content="Button" Height="34" HorizontalAlignment="Left" Margin="19,12,0,0" Name="button1" VerticalAlignment="Top" Width="90" Click="button1_Click" />
</Grid>
That would do the same trick in a different (and in my opinion better) way.
I hope that helps you.
Upvotes: 1