show context menu only on tabcontrol - wpf

I am trying to add a context menu that has "Close" and "Close all but this" like in IE8.
This menu should be displayed when I click on the tab but not on tabitem.
How can i do this?

I believe you want the ContextMenu to appear only when user clicks on the Header of TabItem and not the content area of the TabControl.
If so, you can define a template for Header. See sample code below.
Note:
- The Context menu will appear only when you click on the text part (and not rest of the blank area) of the TabItem Header. If you want for the whole Tab Header area, you will need to modify the ControlTemplate for TabItem.
Sample Code:
<Window x:Class="WpfApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="tabHeaderTemplate">
<ContentPresenter Width="Auto" Content="{TemplateBinding Content}">
<ContentPresenter.ContextMenu>
<ContextMenu>
<MenuItem Header="Close Tab" />
<MenuItem Header="Close Other Tabs" />
<Separator />
<MenuItem Header="New Tab" />
</ContextMenu>
</ContentPresenter.ContextMenu>
</ContentPresenter>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Tab 1"
HeaderTemplate="{StaticResource tabHeaderTemplate}">
<Label>Data for first Tab goes here</Label>
</TabItem>
<TabItem Header="Tab 2"
HeaderTemplate="{StaticResource tabHeaderTemplate}">
<Label>Data for second Tab goes here</Label>
</TabItem>
<TabItem Header="Tab 3">
<Label>Data for third Tab goes here</Label>
</TabItem>
</TabControl>
</Grid>
</Window>

Is this what you need:
Code:
<TabControl Margin="28,25,57,38" Name="tabControl1">
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.ContextMenu>
<ContextMenu Name="ct1" >
<MenuItem Name="Item1" Header="Close"/>
<MenuItem Name="Item2" Header="CloseOtherThankThis" />
</ContextMenu>
</TabItem.ContextMenu>
<Grid>
<Label Margin="41,75,22,64" Name="label1">First Tab</Label>
</Grid>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.ContextMenu>
<ContextMenu Name="ct2">
<MenuItem Name="Item3" Header="Close"/>
<MenuItem Name="Item4" Header="CloseOtherThankThis" />
</ContextMenu>
</TabItem.ContextMenu>
</TabItem>
</TabControl>
Are you talking about the case in which there should be no duplicate context menu?

Related

WPF: Can not select first TabItem in TabControl with nested TabControls

I'm facing a strange issue with nested TabControls in WPF.
In my Home Window I need to put a TabControl inside another TabItem, in order to create different menu levels.
Since I need to have no default-selected TabItem, I'm using TabControl.Loaded event like so:
private void TabControl_Loaded(object sender, RoutedEventArgs e)
{
((TabControl)sender).SelectedItem = null;
}
The issue is: first TabItem of nested TabControl is not selectable, unless selecting the second one then clicking again on the first header.
I created a sample project to demonstrate the problem.
XAML:
<Window x:Class="TabControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TabControlTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TabControl Loaded="TabControl_Loaded">
<TabItem>
<TabItem.Header>
<Label Content="Menu 1" />
</TabItem.Header>
<Grid>
<TabControl Loaded="TabControl_Loaded">
<TabItem>
<TabItem.Header>
<Label Content="Sub-Menu 1" />
</TabItem.Header>
<Grid>
<Button Content="Button in subitem 1" Margin="82,131,553,89" />
</Grid>
</TabItem>
<TabItem>
<TabItem.Header>
<Label Content="Sub-Menu 2" />
</TabItem.Header>
<Grid>
<Button Content="Button in subitem 2" Margin="429,69,206,151" />
</Grid>
</TabItem>
</TabControl>
</Grid>
</TabItem>
<TabItem>
<TabItem.Header>
<Label Content="Menu 2" />
</TabItem.Header>
<Grid>
<Button Content="Button in Hello 2" Height="NaN" Margin="274,65,54,237" Width="NaN" />
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
If I disable the Loaded event, there are no issues.
Any help would be appreciated.
EDIT: I uploaded the sample project here.
Instead of handling the Loaded event, I believe you can add an invisible TabItem to prevent the first "real" tab from being selected initially:
<TabControl>
<TabItem Visibility="Collapsed" />
<TabItem>
<TabItem.Header>
<Label Content="Menu 1" />
</TabItem.Header>
<Grid>
<TabControl>
<TabItem Header="" Visibility="Collapsed" />
<TabItem>
<TabItem.Header>
<Label Content="Sub-Menu 1" />
</TabItem.Header>
<Grid>
<Button Content="Button in subitem 1" Margin="82,131,553,89" />
</Grid>
</TabItem>
<TabItem>
<TabItem.Header>
<Label Content="Sub-Menu 2" />
</TabItem.Header>
<Grid>
<Button Content="Button in subitem 2" Margin="429,69,206,151" />
</Grid>
</TabItem>
</TabControl>
</Grid>
</TabItem>
<TabItem>
<TabItem.Header>
<Label Content="Menu 2" />
</TabItem.Header>
<Grid>
<Button Content="Button in Hello 2" Height="NaN" Margin="274,65,54,237" Width="NaN" />
</Grid>
</TabItem>
</TabControl>
Another potential workaround would be to bind the TabControl to a source collection using the ItemsSource property.
You could handle window.contentrendered and set the selectedindex to -1 on the outer tabcontrol:
private void Window_ContentRendered(object sender, EventArgs e)
{
tc.SelectedIndex = -1;
}
I've named that tabcontrol tc, obviously:
<Grid>
<TabControl x:Name="tc">
<TabItem>
When I handle loaded on the outer tabcontrol, the same approach works.
private void tc_Loaded(object sender, RoutedEventArgs e)
{
tc.SelectedIndex = -1;
}

Children Tabs in Wpf

I have been looking for a way to implement a child tab control inside a tab control(sort of like multi level tab controls).
but haven't found any materials for that, i can implement dynamically that at run time in Xaml.cs though, but i want to define it into Window.Xaml only, so that i can embed my controls into it.
Figure Below is an sample of the ui.
Kindly Suggest me the way to do it.
This will work for you.
<TabControl>
<TabItem Header="Tab1">
<TabControl Margin="10">
<TabItem Header="Tab1">
<TabControl Margin="20">
<TabItem Header="Tab1">
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center">
<DockPanel >
<TextBlock Text="Name:" VerticalAlignment="Center" DockPanel.Dock="Left"></TextBlock>
<TextBox Text="Nitesh" Margin="10,0,0,0" DockPanel.Dock="Right"></TextBox>
</DockPanel>
<StackPanel Orientation="Horizontal" Margin="10">
<Button Margin="5">OK</Button>
<Button Margin="5">Cancel</Button>
</StackPanel>
</StackPanel>
</TabItem>
<TabItem Header="Tab2"></TabItem>
</TabControl>
</TabItem>
<TabItem Header="Tab2"></TabItem>
</TabControl>
</TabItem>
<TabItem Header="Tab2"></TabItem>
</TabControl>

How to resize TabContols by holding the emptyspace in the tab strip

I have two tab controls stacked (using dockpanel) in a way that the empty space overlaps of their Tabstrips overlaps. I have to let users to resize these two tabcontrols height, especially the bottom one if they need.. Is there any way i can hold the emptyspace next to TabHeaders and drag it to resize?
<DockPanel>
<TabControl DockPanel.Dock="Bottom" Height="200" Margin="0,-20,0,0">
<TabItem Header="tab 1"></TabItem>
<TabItem Header="tab2"></TabItem>
</TabControl>
<TabControl TabStripPlacement="Bottom" FlowDirection="RightToLeft">
<TabItem Header="Tab 3" FlowDirection="LeftToRight"></TabItem>
<TabItem Header="Tab 4" FlowDirection="LeftToRight"></TabItem>
</TabControl>
</DockPanel>
Any pointers would be greatly appreciated.
Found the answer.
<osc:DockPanelSplitter DockPanel.Dock="Bottom" Margin="0,-20,0,0" Height="20" Panel.ZIndex="-1"/>
<TabControl TabStripPlacement="Bottom" FlowDirection="RightToLeft">
<TabItem Header="Tab 3" FlowDirection="LeftToRight"></TabItem>
<TabItem Header="Tab 4" FlowDirection="LeftToRight"></TabItem>
</TabControl>
</DockPanel>
Key is Panel.Zindex on DockPanelSplitter

DropDownButton content binding issue

I'm trying to add MenuItems into a DropDropButton control and control the visibility
of the buttons using the IsSelected property of TabItem, however the visibility
of the MenuItems do not change. I applied the same binding on a standard
button it the visibility works as expected. Does anyone know what is going on here?
Here is a sample of what I'm trying to do:
<StackPanel>
<Button Content="Hi" Visibility="{Binding ElementName=tabItem1, Path=IsSelected, Converter={StaticResource VisibilityConverter}}"/>
<toolkitEx:DropDownButton Content="Button 1">
<toolkitEx:DropDownButton.DropDownContent>
<StackPanel>
<MenuItem Header="Visibile for tabItem1" Visibility="{Binding ElementName=tabItem1, Path=IsSelected, Converter={StaticResource VisibilityConverter}}"/>
<MenuItem Header="Visibile for tabItem2" Visibility="{Binding ElementName=tabItem2, Path=IsSelected, Converter={StaticResource VisibilityConverter}}"/>
</StackPanel>
</toolkitEx:DropDownButton.DropDownContent>
</toolkitEx:DropDownButton>
<TabControl HorizontalAlignment="Stretch" Name="tabControl1" VerticalAlignment="Stretch" >
<TabItem Header="tabItem1" x:Name="tabItem1">
<Grid />
</TabItem>
<TabItem Header="tabItem2" x:Name="tabItem2">
<Grid />
</TabItem>
</TabControl>
</StackPanel>
Thanks!

How to reuse layouts in WPF

I'm trying to create a application that will be tabbed where each tab will have a button area and a view area.
Now each tab will essentially have the same layout just different things in the layout and I wanted to be able to reuse the same layout so that I won't have to change at many places ( it's just not good programming ). Can I accomplish this using resources or perhaps Styles.
Please supply a light code example if possible.
EDIT: I've decided to add an example of what I'm trying to do because I'm still not getting it.
Under each TabItem I'm trying to recreate this grid (It's a bit more complicated but you get the idea ):
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Margin="10"
BorderBrush="{StaticResource MediumColorBrush}"
CornerRadius="10"
BorderThickness="2"
Grid.Row="0">
<!-- First content goes here -->
</Border>
<Border Margin="10"
BorderBrush="{StaticResource MediumColorBrush}"
CornerRadius="10"
BorderThickness="2"
Grid.Row="1">
<!-- Second content goes here -->
</Border>
</Grid>
as you can see also the 2 borders are the same. Now I need to put some content placeholder where my comments are. I wan't to declare this Grid layout in a resource dictionary and then where I use it put seperate content into each border.
I may have alot of TabItems so repeating this code isn't a good idea and each Tab page will have different content in the 2 placeholders.
I'm able to use the
<ContentPresenter Content="{Binding}" />
thing but only for 1 content, what happens when there will be more.
Ingo,
Code is always available on MSDN. Check this: UserControl, Custom controls, DataTemplates.
Here are some examples of each approach. For sake of simplicity, let's assume the layout you want to replicate is one line of text with green foreground (in reality it may be really different, but you get the idea).
1. User Control
Xaml:
<UserControl x:Class="WpfApplication1.GreenTextUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock x:Name="txt" Foreground="Green"/>
</UserControl>
C#:
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class GreenTextUserControl : UserControl
{
public string Text
{
get { return txt.Text;}
set { txt.Text = value; }
}
public GreenTextUserControl()
{
InitializeComponent();
}
}
}
Tab control:
<TabControl>
<TabItem Header="Tab 1">
<loc:GreenTextUserControl Text="This is Tab 1"/>
</TabItem>
<TabItem Header="Tab 2">
<loc:GreenTextUserControl Text="This is Tab 2"/>
</TabItem>
<TabItem Header="Tab 3">
<loc:GreenTextUserControl Text="This is Tab 3"/>
</TabItem>
</TabControl>
2. Custom control
C#:
public class GreenTextBlock : TextBlock
{
public GreenTextBlock()
{
Foreground = Brushes.Green;
}
}
TabControl:
<TabControl>
<TabItem Header="Tab 1">
<loc:GreenTextBlock Text="This is Tab 1"/>
</TabItem>
<TabItem Header="Tab 2">
<loc:GreenTextBlock Text="This is Tab 2"/>
</TabItem>
<TabItem Header="Tab 3">
<loc:GreenTextBlock Text="This is Tab 3"/>
</TabItem>
</TabControl>
If your layout is more complex than textblock, custom controls also allows you to define it in XAML but it differs from UserControls.
3. DataTemplate
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:Array x:Key="GreenText" Type="{x:Type System:String}">
<System:String>This is Tab 1</System:String>
<System:String>This is Tab 2</System:String>
<System:String>This is Tab 3</System:String>
</x:Array>
<!--Tab item content data template-->
<DataTemplate x:Key="GreenTextTemplate">
<TextBlock Text="{Binding}" Foreground="Green"/>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl ItemsSource="{StaticResource GreenText}">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="ContentTemplate" Value="{StaticResource GreenTextTemplate}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Window>
That's it :). Hope it helps.
TabItem is a ContentControl which allows any child content, but also allows templating of the content, which is exactly what you're trying to do. You can use a DataTemplate like this to do your shared layout. ContentPresenter is the placeholder for the different content of each TabItem.
<DataTemplate x:Key="ButtonViewerTemplate">
<DockPanel>
<Button DockPanel.Dock="Bottom" Content="OK"/>
<Button DockPanel.Dock="Bottom" Content="Cancel"/>
<Border Background="Aqua" BorderBrush="Red" BorderThickness="2" Padding="5">
<ContentPresenter Content="{Binding}" />
</Border>
</DockPanel>
</DataTemplate>
To use the template just set it to each TabItem's ContentTemplate. This works with anything derived from ContentControl.
<TabControl>
<TabItem ContentTemplate="{StaticResource ButtonViewerTemplate}" Header="Some Buttons">
<UniformGrid>
<Button Content="XXXXX"/>
<Button Content="XXXXX"/>
<Button Content="XXXXX"/>
<Button Content="XXXXX"/>
</UniformGrid>
</TabItem>
<TabItem ContentTemplate="{StaticResource ButtonViewerTemplate}" Header="All Blue">
<Border Background="Blue" MinHeight="50"/>
</TabItem>
<TabItem ContentTemplate="{StaticResource ButtonViewerTemplate}" Header="Image">
<Image Source="http://i.msdn.microsoft.com/Platform/Controls/StoMastheadMSDN/resources/logo_msdn.png"/>
</TabItem>
</TabControl>

Resources