Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to close Tab with a close button in WPF?

Tags:

c#

wpf

xaml

I am working on a WPF app where it creates new tab upon clicking a button. That is working fine. I am having hard time in figuring out how to have a close button, like a X next to the Tab header and close the selected tab?

MainWindow.xaml

<Grid>
        <StackPanel Name="listConnections" Grid.Column="0" Background="#4682b4" Margin="0,0,0,-0.2" >
        </StackPanel>            
        <TabControl Name="tabConnections" Grid.Column="1" TabStripPlacement="Top" Margin="0,0,0.4,-0.2">
        </TabControl>
    </Grid>
</Window>

add Tab method to create new tabs upon button click MainWindow.xaml.cs

public void addTab(Connection connection)
{
    TabItem tab = new TabItem();
    tab.Header = connection.name;
    tabConnections.Items.Add(tab);
}

Is there a simple way to do the close button?

like image 683
Truecolor Avatar asked Apr 20 '17 19:04

Truecolor


2 Answers

Answer to question:

  1. Create tab.

    Use a stack panel for aligning the text box and close image horizontally. Check the example below.

  2. Remove tab when clicking on close.

    For closing a tab create an event handler in the code behind for handling the click. In this event handler you can simply use:

    tabConnections.Items.RemoveAt(tabConnections.SelectedIndex);
    

    Why do I use the selected index? This is because when you click the tab the tab becomes the selected one. where after the click event handler could remove the tab with the index that is equal to the selected index.

Example:

In this example, I create dynamic content for the TabControl. By using your own UserControls as content. Also, this example will provide a closing image in the tab. So first create a Tab class and the view modal behind it.

The tab

// This class will be the Tab int the TabControl
public class ActionTabItem
{
    // This will be the text in the tab control
    public string Header { get; set; }
    // This will be the content of the tab control It is a UserControl whits you need to create manualy
    public UserControl Content { get; set; }
}

View modal

/// view model for the TabControl To bind on
public class ActionTabViewModal
{
    // These Are the tabs that will be bound to the TabControl 
    public ObservableCollection<ActionTabItem> Tabs { get; set; }

    public ActionTabViewModal()
    {
        Tabs = new ObservableCollection<ActionTabItem>();
    }

    public void Populate()
    {
        // Add A tab to TabControl With a specific header and Content(UserControl)
        Tabs.Add(new ActionTabItem { Header = "UserControl 1", Content = new TestUserControl() });
        // Add A tab to TabControl With a specific header and Content(UserControl)
        Tabs.Add(new ActionTabItem { Header = "UserControl 2", Content = new TestUserControl() });
    }
}

Now we need to create the xaml whits binds the tab item to the viewmodel above.

  1. Bind The Header from the Action Tab item to a TextBlock in the TabControl

  2. Give the image control a path from the close button image

  3. Bind the Content to the UserControl from the Action Tab item

  4. Use A stack panel for the Header Info and close image and align it horizontally.

    <Grid>
        <TabControl x:Name="actionTabs" DockPanel.Dock="Right" Background="White">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Height="21" Width="100">
                        <TextBlock Width="80" Text="{Binding Header}"/>
                        <Image Source="PathToFile\close.png" Width="20" Height="20" MouseDown="Image_MouseDown"/>
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <UserControl Height="800" Width="1220" Content="{Binding Content}" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>

In the code behind

public partial class Window1 : Window
{
    private ActionTabViewModal vmd;

    public Window1()
    {
        InitializeComponent();
        // Initialize viewModel
        vmd  = new ActionTabViewModal();
        // Bind the xaml TabControl to view model tabs
        actionTabs.ItemsSource = vmd.Tabs;
        // Populate the view model tabs
        vmd.Populate();
    }

    private void Image_MouseDown(object sender, MouseButtonEventArgs e)
    { 
        // This event will be thrown when on a close image clicked
        vmd.Tabs.RemoveAt(actionTabs.SelectedIndex);
    }
}

Result:

like image 195
Timon Post Avatar answered Nov 12 '22 09:11

Timon Post


This worked for me

  1. Create usercontrol with
<Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Column="2" Content="X"  Height="19" OnClick="button_close_Click" HorizontalAlignment="Right" Margin="0,3,4,0" 
          VerticalAlignment="Top" Width="20" FontFamily="Courier" 
          FontWeight="Bold" 
          FontStretch="Normal"
          FontSize="14" Background="IndianRed"/>
        <Label Grid.ColumnSpan="2" Height="23" HorizontalAlignment="Left" 
          Margin="4,1,0,0" VerticalAlignment="Top" 
          FontFamily="Courier" FontSize="12" x:Name="NameLabel"/>
    </Grid>

2.The user control class

public partial class CloseHeader : UserControl
    {
        MainWindow _shell;
        int _index;
        public CloseHeader(MainWindow shell, int index, string headerName)
        {
            InitializeComponent();
            _shell = shell;
            _index = index;
            NameLabel.Content = headerName;
        }

        private void button_close_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            _shell.CloseTab(_index);
        }
    }
  1. In the mainwindow

    List<int> _tabs = new List<int>();

    public void AddNewTab(HomeFunctions function)//HomeFunctions is an enum
    {
        int newIndex = tabControl.Items.Count;
        _tabs.Add(newIndex);
        switch (function)
        {
            case HomeFunctions.Settings:
                tabControl.Items.Add(new TabItem { Content = new SettingsControl(this), Width = 100, Header = new CloseHeader(this, newIndex, HomeFunctions.Settings.ToString()) });
                break;
        }
        tabControl.SelectedIndex = newIndex;
    }

    public void CloseTab(int tabId)
    {
        tabControl.Items.RemoveAt(_tabs.IndexOf(tabId));//tabControl.Items.RemoveAt(_tabs.IndexOf(tabId) + 1); if you have a non closeable tab first like i do in mine
      _tabs.Remove(tabId);
    }

like image 1
salman_sali Avatar answered Nov 12 '22 11:11

salman_sali