user1447343
user1447343

Reputation: 1457

How to add a TextBox to TabItem?

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

Answers (1)

Mats Magnem
Mats Magnem

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

Related Questions