WPF: apply style only to one tabcontrol containing other tabControl - wpf

In my wpf application, I have a tabControl (parent) that contains another tabcontrol (child).
I would like to apply a style to the tabItem of the parent tabControl without affecting the child one.
I tried with this:
<TabControl x:Name="Parent" TabStripPlacement="Left"
ItemsSource="{Binding Path=ParentTabItems, Mode=OneWay}" >
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<!-- template is defined here-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter>
<ContentPresenter.Content>
<!--Here there is the child TabControl-->
</ContentPresenter.Content>
</ContentPresenter>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
But this results in applying the style also to the child tabControl TabItem.
How can I apply the style only to the parent tabItem leaving the child TabControl using the default style defined in the application?

You should be able to use the TabControl.ItemContainerStyle to set a named Style on the TabItems of the outer TabControl. Try this:
In Resources:
<Style x:Key="ItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<!-- template is defined here-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
...
<TabControl x:Name="Parent" TabStripPlacement="Left"
ItemsSource="{Binding Path=ParentTabItems, Mode=OneWay}"
ItemContainerStyle="{StaticResource ItemStyle}">
<TabControl.Resources>
<Style TargetType="{x:Type TabPanel}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</TabControl.Resources>
</TabControl>

Related

WPF write ControlTemplate for a ContentControl when its content type is UserControl

I have a ContentControl like this:
<ContentControl>
<userControls:TestControl/>
</ContentControl>
OR like this [when i have PRISM system]:
<ContentControl prism:RegionManager.RegionName="TestView"/>
I see the final UserControl well until this step when i start the program.
In the above samples the Content type is UserControl. Now i want give a ControlTemplate to this ContentControl. Then i created a style named StyleTest and used it in my Xaml:
<ContentControl Style="{StaticResource StyleTest}"> .....
My style:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="10">
<Border CornerRadius="10" BorderBrush="#ffffffff" BorderThickness="5">
<StackPanel>
<ContentPresenter Content="{Binding}"/>
<TextBlock>Some additional text to test template</TextBlock>
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But when i start the program the UserControl can not be seen and i just see this text and a border around it: Some additional text to test template
What i must write instead of above line of code to see my UserControl again with a white border around it?
Why the UserControl not showing with above code (above style)?
There are 3 ways to do this.
- by setting the ContentTemplate
- by setting the Template
- or using the Border directly and apply a style.
In this case I would use the Border and apply a style because it looks like the ContentControl is only used to do add a styled Border.
<StackPanel>
<StackPanel.Resources>
<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="5" />
<Setter Property="CornerRadius" Value="10" />
<Setter Property="Margin" Value="10" />
</Style>
<Style x:Key="ContentTemplateStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border Style="{StaticResource BorderStyle}">
<!-- Bind to the DataContext of the DataTemplate which is the Content of the ContentControl -->
<!-- <ContentPresenter Content="{Binding}" />-->
<!-- TemplateBinding improves performance -->
<ContentPresenter Content="{TemplateBinding Content}" />
<!-- Using the TemplatedParent -->
<!--<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>-->
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ControlTemplateStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Style="{StaticResource BorderStyle}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<ContentControl Style="{StaticResource ContentTemplateStyle}">
<Button>ContentTemplateStyle</Button>
</ContentControl>
<ContentControl Style="{StaticResource ControlTemplateStyle}">
<Button>ControlTemplateStyle</Button>
</ContentControl>
<Border Style="{StaticResource BorderStyle}">
<Button>BorderStyle</Button>
</Border>
</StackPanel>
datacontext is a type?. Normally it will be inherited in the visual tree so I think it should be left blank.
Content is the content of the parent. Normally you can use a template binding or set the content source property.
but using this template will only show you a white border around content. The original template is lost. So you should provide the entire template for the control.
Now maybe the control contains margin and border properties and you can set those from your style and leave the original template in place.
I found my mistake place and changed this part of my codes:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
To this one:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate >
When i play with Template its effects is on inner content of the ContentControl (in this question: template of the UserControl) But when i play with ContentTemplate, its effects is on ContentControl layout.
ContentPresenter tag is same and it works now...
<ContentPresenter Content="{Binding}"/>

WPF: How to use BasedOn Style

I am new to WPF and I created the following simple style example. But it doesn't work properly and button's content doesn't show although I can still click on it. Can anyone tell me why it is broken?
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Blue"
BorderThickness="5"
Background="Aqua"
Width="80"
Height="40">
<ContentPresenter></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Grid" x:Name="GridWithMarginStyle">
<Setter Property="Margin" Value="12"></Setter>
</Style>
</Window.Resources>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<EventSetter Event="Button.Click" Handler="ButtonHandler" />
<Setter Property="Background" Value="Red"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
</Style>
</StackPanel.Resources>
<Button Name="OkBtn">OK</Button>
<Button Name="CancelBtn" Click="CancelBtn_Click">Cancel</Button>
</StackPanel>
You are using the BasedOn property in the correct way. The problem is that your ContentPresenter is not binded to the control it renders (i.e. the button).
Just try to replace your ControlTemplate XAML with this one:
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderBrush="Blue"
BorderThickness="5"
Background="Aqua"
Width="80"
Height="40">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
By using TemplateBinding you can bind the ContentPresenter to the Content property of your templated control.

WPF TabControl apply TabItem style insead of overriding it (while using ItemSource)

I have a parent TabControl with a custom TabItem style:
<TabControl ItemsSource="{Binding TabViewModels}" SelectedIndex="0" Padding="0,0,0,0" BorderThickness="0,0,0,0" Panel.ZIndex="1">
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}" >
<Border Name="Border" CornerRadius="6,6,0,0" Margin="0,0,2,2">
<ContentPresenter TextBlock.TextAlignment="Center" TextBlock.FontSize="14"
Height="40" Width="auto" Content="{Binding Path=TabName}" Margin="12,2,12,2"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#00B6FA" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TabPanel">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding Path=. }"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Inside one of the Tabs of the parent TabControl I have a child TabControl.
The problem is that the child TabControl automaticly takes the custom TabItem style because I override it as you can see above. What I want is that the child TabControl takes the default windows style for the TabItems.
Is this possible to apply the custom Tab Item instead of override it and using an ItemSource?
You can specify the style for the nested TabControl via its Style property:
<TabControl Style="{DynamicResource ResourceKey={x:Type TabControl}}">
...
</TabControl>
The default style key is usually the type of the control, hence {x:Type TabControl}.
Update:
I assume that you're using so-called implicit style for tab items, which is defined in the top-level TabControl's resources dictionary. By implicit style I understand a style without a key and with TargetType specified. To apply a default style to TabItem controls within a particular nested TabControl, simply add an empty implicit style to its resources dictionary, like so:
<TabControl x:Name="OuterTabControl">
<TabControl.Resources>
<Style TargetType="TabItem">
<!-- your style definition -->
</Style>
</TabControl.Resources>
...
<TabControl x:Name="InnerTabControl">
<TabControl.Resources>
<Style TargetType="TabItem"/>
</TabControl.Resources>
</TabControl>
...
</TabControl>
To avoid un-styling nested tab controls, see AnjumSKhan's answer, which puts the outer control's style inside a trigger whose binding cleverly targets just the one control:
<TabControl.Resources>
<Style TargetType="TabItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TabControl, AncestorLevel=2}}" Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" Background="Red">
<ContentPresenter ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style> </TabControl.Resources>

How can I style certain WPF listboxes to be radio buttons?

I want to style some of my listboxes' items to be radiobuttons. Here is the code I have but this style gets applied to every listboxitem.
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton Content="{TemplateBinding Content}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
How can I do something so I can designate a listbox to have radio buttons. I imagine the designation would go something like this:
<ListBox Name="ListBox1" Width="120" Visibility="Visible" Background="{x:Null}" BorderThickness="0" Style="{StaticResource radioListBox}">
I know part of the problem is that this only styles listboxitems but I am not sure how to style the listbox itself. I would of course prefer to add in the background and border properties.
Any help would be appreciated.
You need to give your Style a key:
<Window.Resources>
<Style x:Key="radioListBoxItem" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton Content="{TemplateBinding Content}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And then you would apply it to a ListBox like:
<ListBox ItemContainerStyle="{StaticResource radioListBoxItem}" />
If you want to create a style for a ListBox that contains the radio list box items, and some other properties, you could do that too:
<Style x:Key="radioListBox" TargetType="{x:Type ListBox}">
<Setter Property="ItemContainerStyle" Setter="{StaticResource radioListBoxItem}" />
<Setter Property="Background" Value="Navy" />
</Style>
And you'd apply it:
<ListBox Style="{StaticResource radioListBox}" />

Binding to Control which applied the Style/Template

I want to (re-)template a Control, for example a ComboBox.
XAML:
<ComboBox Style="{StaticResource MyComboBoxStyle}" ... >
<!-- ... -->
</ComboBox>
In the ControlTemplate I want to have a Button.
ResourceDictionary:
<Style x:Key="MyComboBoxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<!-- ... -->
<Button Command="{TemplateBinding Tag}" CommandParameter="{Binding ???}" />
<!-- ... -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But I want to set the CommandParameter to the Control which applied the Template (in this example the ComboBox).
How can I solve this?
Ok, i found the right solution.
I have set the Binding to Binding RelativeSource={RelativeSource TemplatedParent}
<Style x:Key="MyComboBoxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<!-- ... -->
<Button Command="{TemplateBinding Tag}" CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}}" />
<!-- ... -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources