1

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;
user1447343
  • 1,417
  • 4
  • 18
  • 24

1 Answers1

1

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.

Mats Magnem
  • 1,375
  • 1
  • 10
  • 21
  • Edit: it's working now... Thanks for your suggestion, but the textbox is not shown... – user1447343 Jan 16 '13 at 17:30
  • The textbox is not shown because it is Top aligned and does not have a Height specified, thus having an ActualHeight of 0. This is a terribly bad solution, though, which could be replaced by 2 lines of XAML. – Federico Berasategui Jan 16 '13 at 17:32
  • You should consider using a DataTemplate to achieve this. The solution has more of a WinForms flavor to it. Check this out: http://stackoverflow.com/questions/1870564/need-help-with-tabcontrol-itemtemplate – Jason Tyler Jan 16 '13 at 17:50
  • I would personally not use code to achieve this. I would be using Custom Controls or simply ItemTemplate, depending if the tabs sould vasy or stay the same. But from the question, it seemed to me like the start was done code. So I just continued in the pattern I thought it was started in. – Mats Magnem Jan 16 '13 at 21:52
  • I improved my answer with the solution along the way how I would really solve it. – Mats Magnem Jan 16 '13 at 22:39