How to define a TabItem Header Template in WPF - wpf

I'm learning WPF and I read an article about Templating. So I wanted to write some code, but i got stuck.
What do I want to do? My Application has A TabControl and I want that all the tabs has the same Layout. A stackpanel and in the stackpanel an Image and a Textblock.
Now i don't know how the content can be set afterwards. Do I need a ContentPresenter?
<ControlTemplate x:Key="TabTemplate">
<StackPanel Orientation="Horizontal">
<Image></Image>
<TextBlock></TextBlock>
</StackPanel>
</ControlTemplate>

In your resource dictionary add a Style with your desired template:
<Style x:Key="CustomTabItemStyle"
TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="Root"
Width="180"
Height="45"
Margin="0,0,0,0"
SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal">
<Image Width="90"
Margin="10"
VerticalAlignment="Center"
Source="pack://Application:,,,/img/myTabImage.png"
Stretch="Uniform" />
<TextBlock x:Name="contentPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Focusable="False"
FontSize="16"
Foreground="White"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Text="{TemplateBinding Header}" />
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Don't forget to edit your Image. If all tabs has same image then just change a Source link, otherwise, you may need another binding, e.g Content.
And then simply use this style in your TabItems:
<TabControl Margin="0,5,0,0"
FocusVisualStyle="{x:Null}">
<TabItem Header="My First Tab"
IsSelected="{Binding FirstTabItemSelected}"
Style="{DynamicResource CustomTabItemStyle}">
...
</TabItem>
<TabItem Header="My Second Tab"
IsSelected="{Binding SecondTabItemSelected}"
Style="{DynamicResource CustomTabItemStyle}">
...
</TabItem>
</TabControl>

Related

How can I access child element of any object by using style?

I'm faced with a problem about to find child element. I want to access TextBlock element inside Label. But I can't find it.
Here is my MainWindow.xaml code:
<Label x:Name="text" Style="{DynamicResource labelstyle}">
<TextBlock>asdasdasd</TextBlock>
</Label>
Here is my style code:
<Style x:Key="labelstyle" TargetType="Label">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border BorderThickness="2" BorderBrush="Red">
<TextBox x:Name="textBox" Text="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type TextBlock},
AncestorLevel=2},Path=Text}">
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to bind TextBox's Text property to Label inside TextBlock's Text property. What should I do ?
I hope I made my self clear.
Thank you.
Below is a sample image:
Instead of using a TextBlock in your label, just leave it in your template and have it reference the Label Content for the text to be displayed.
Below is an example:
<Label x:Name="text" Content="asdasdasd" Style="{StaticResource labelstyle}"/>
and for the styling/template
<Style x:Key="labelstyle" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderThickness="2" BorderBrush="Red">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style>
This should provide you with the centered text in the red border you seem to be trying to achieve.
Hopefully this helps you a bit.
This will let you display text through a binding and the user will be able to select it, but not type in the TextBox. If you want to be able to also type in the TextBox, remove the IsReadOnly="True"
<Label Height="30" Width="150">
<Label.Template>
<ControlTemplate TargetType="{x:Type Label}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
MinWidth="26"
Margin="2"
Source="{Binding myImageSource}"/>
<TextBox Grid.Column="1"
IsReadOnly="True"
Text="{Binding myTextValue}"
Margin="5,2"/>
</Grid>
</ControlTemplate>
</Label.Template>
</Label>

creating Icon View mode for ListView WPF

I'm Trying to change listView GridView to IconView, as you see in the screenshot, each item is taking a row.
Style XAML
<UserControl.Resources>
<Style x:Key="FileItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Width" Value="50"/>
<Setter Property="Margin" Value="5,5,5,5"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" Width="50">
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2.5"/>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter />
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
ListView XAML
<ListView ItemContainerStyle="{DynamicResource FileItemStyle}" HorizontalAlignment="Left" Height="194.667" Margin="11,77.666,0,0" VerticalAlignment="Top" Width="368.667" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" UseLayoutRounding="False">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Height="50">
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" Height="50" VerticalAlignment="Stretch" Width="50" CornerRadius="2.5"/>
<StackPanel>
<Image x:Name="Img" Source="BtnImg/Computer.png" Stretch="None" Margin="9,0,9,0" Width="32" Height="32"/>
<TextBlock x:Name="PCName" Margin="0" TextWrapping="Wrap" Height="18" HorizontalAlignment="Stretch" TextAlignment="Center"><Run Text="{Binding Content}"/></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListBoxItem Content="ddd"/> <!--**-->
<ListViewItem Content="zczxcz"/>
</ListView>
I've tried to use MDSN example : How to: Create a Custom View Mode for a ListView and modify it to get what I need, but it didn't work with me, I actually couldn't understand the example clearly, anyone can Simplify how can I create a View mode? Do I have to create an overrided ViewBase class?
Thanks in advance
Using the same exact Code Behind as My Answer to your previous question:
<Style x:Key="FileItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="5,5,5,5"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" >
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2.5"/>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then:
<ListView ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedItem="{Binding SelectedComputer, RelativeSource={RelativeSource AncestorType=Window}}"
ItemContainerStyle="{StaticResource FileItemStyle}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding Name}"/>
<Rectangle Height="32" Width="32" Fill="Blue"/>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Result:
Remove the hardcoded Width and Heights
Replace the blue rectangle for your Image.
Add some Triggers in the ControlTemplate so that you get highlighting when IsSelected="True"
Simply change the ItemsPanel of any ItemsControl in order to define how items are laid out.
Using a WrapPanel, you get a layout similar to Windows Explorer, where items are placed horizontally until there is no more horizontal space and then another "row" is created. Run the example and resize the Window to see this.
Bottom line: NO, you don't need custom code to customize the UI in WPF. It can be done with the existing controls and some XAML. Please read the "Alternatives to Writing a New Control" section in MSDN: Control Authoring Overview

Docked control tabs not rendering correclty

I'm working on customizing a user control containing a tab control child element. The user control docks to the side of the main window. I want the tab items to orient based on the docking position, eg. left docked tab items rotate 90 degrees to lay along the side. I have the tabs aligning correctly by binding to the attached property DockPanel.Dock. The problem is that when the tabs are rendered they are disconnected by a line from the tab control. I can manually set the (DockPanel.Dock) property for the outer user control object and the tabs docked along that direction draw correctly but the other tabs are separated by a line.
Here is the TabDockControl XML:
<UserControl x:Class="AnimationMotionCaptureStudio.TabDockControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" x:Name="Root" DockPanel.Dock="Left">
<Grid>
<TabControl Height="Auto" HorizontalAlignment="Stretch" Name="tabControl1" VerticalAlignment="Stretch" Width="Auto" TabStripPlacement="{Binding Path=(DockPanel.Dock),ElementName=Root}">
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Padding" Value="2" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(DockPanel.Dock), ElementName=Root}" Value="Left">
<Setter Property="Padding" Value="2" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="90" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(DockPanel.Dock), ElementName=Root}" Value="Right">
<Setter Property="Padding" Value="5" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="-90" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TabControl.Resources>
<TabItem Header="{Binding Path=(DockPanel.Dock), ElementName=Root}" Name="tabItem1">
<Grid>
<Border BorderBrush="Silver" BorderThickness="1" Height="Auto" HorizontalAlignment="Stretch" Name="border1" VerticalAlignment="Stretch" Width="Auto" />
</Grid>
</TabItem>
</TabControl>
</Grid>
The code behind file has no additional code added beyond the constructor generated by VS2010.
And the MainWindow XML usage of the control:
<DockPanel Grid.Row="1" Height="Auto" HorizontalAlignment="Stretch" Name="MainDockPanel" VerticalAlignment="Stretch" Width="Auto" >
<DockPanel.Children>
<StatusBar Height="23" Name="statusBar1" Width="Auto" DockPanel.Dock="Bottom" Background="#FF00476D" />
<AMCS:TabDockControl DockPanel.Dock="Left">
</AMCS:TabDockControl>
<AMCS:TabDockControl DockPanel.Dock="Right">
</AMCS:TabDockControl>
<AMCS:TabDockControl DockPanel.Dock="Bottom">
</AMCS:TabDockControl>
<Border BorderBrush="Silver" BorderThickness="2" Height="Auto" Name="border1" Width="Auto" DockPanel.Dock="Top" Background="#FF898888">
<Image Height="Auto" HorizontalAlignment="Stretch" Name="D3DImage" Stretch="Fill" VerticalAlignment="Stretch" Width="Auto" MouseLeftButtonDown="D3DImage_MouseLeftButtonDown" MouseLeftButtonUp="D3DImage_MouseLeftButtonUp" MouseMove="D3DImage_MouseMove" Grid.RowSpan="1" Grid.Row="1" MouseWheel="D3DImage_MouseWheel">
<Image.Source>
<i:D3DImage x:Name="D3DImageSource"/>
</Image.Source>
</Image>
</Border>
</DockPanel.Children>
</DockPanel>
Any suggestions for how to set this up to render the tabs correctly would be greatly appreciated.

Reading Content property of a Button into a ConrtolTemplate in a style

I have a style for a button with a ControlTemplate something like this
<Style x:Key="ButtonStyle"
BasedOn="{x:Null}"
TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle"
Fill="#FF04822A"
Stroke="{x:Null}" />
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Heavy"
Foreground="Black"
x:Name="btnText"
TextAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Grid.Row="3"
Grid.Column="5"
Margin="4,0,4,0"
Command="{Binding ResetCommand}"
Content ="Reset Cells"
Style="{StaticResource ButtonStyle}" />
I want the TextBlock to read from the button Content every time its updated.
Add a template binding to the TextBlock:
Text="{TemplateBinding Content}"
You might just want to use a ContentPresenter instead though (as TextBlocks usually only display text).

Setting tooltip to equal content

I'm trying to set a data grid's cell's tooltip to be equal to the text inside of a TextBlock in that cell. What I have so far is this:
<Style x:Key="CellStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Grid>
<TextBlock Margin="2" VerticalAlignment="Center"
HorizontalAlignment="Left" TextWrapping="Wrap" >
<ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
<TextBlock.ToolTip>
<ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
</TextBlock.ToolTip>
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However, what this does is very briefly show the tooltip and then the content in the cell is removed, so nothing shows up at all. Also, setting the tooltip from outside the Template setter is an option, but I'm not sure what the corrent binding is to do that.
My example here is for a simple label but this can be applied to other controls.
<Label Name="lblFormName" Content="Form Elements:" FontWeight="Bold" HorizontalAlignment="Left" Width="295" >
<Label.ToolTip>
<Binding ElementName="lblFormName" Path="Content"/>
</Label.ToolTip>
</Label>
Check out this link: http://msdn.microsoft.com/en-us/library/ms742167.aspx
or this link for a bunch of binding "how-to"s from MS http://msdn.microsoft.com/en-us/library/ms752039.aspx
Have you tried using RelativeSource? I heard of some issues about TemplateBinding vs. RelativeSource (WPF TemplateBinding vs RelativeSource TemplatedParent).
<ContentPresenter Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YourAncestorType}, AncestorLevel=1},Path=Content}" />
Where "YourAncestorType" is the type of the parent you want to find.
Or you could also try the same approach with
<ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" />
See also: http://www.wpfwiki.com/Default.aspx?Page=WPF%20Q5.3&AspxAutoDetectCookieSupport=1
Try removing the ToolTip from the ControlTemplate and defining a separate Setter in the Style for the Tooltip.
Here is the XAML using your sample:
<Style x:Key="CellStyle" TargetType="{x:Type WpfToolkit:DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="WpfToolkit:DataGridCell">
<Grid>
<TextBlock Margin="2" VerticalAlignment="Center"
HorizontalAlignment="Left" TextWrapping="Wrap" >
<ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
<!--<TextBlock.ToolTip>
<ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
</TextBlock.ToolTip>-->
</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text}"/>
</Style>

Resources