I want to show an image and Text on each and every tabItem of my TabControl.
So, I created a Style as follows:
<TabControl.Resources>
<Style TargetType="TabItem">
<Style.Setters>
<Setter Property="Header">
<Setter.Value>
<StackPanel Orientation="Horizontal" Background="#FF2A2A2A" Margin="-7,-2" Cursor="Hand">
<Image Source="{Binding Tag}" Margin="10"/>
<TextBlock Text="{Binding Content}" FontSize="32" Foreground="White" Margin="0,10,10,10"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</TabControl.Resources>
Now in the TabItem:
<TabItem Tag="Images/Plus.png" Content="Create New" />
But I don't see any header on any tabItems??????
You need to use RelativeSource to travel up Visual tree to get your property bindings to work. By default it will search for property in DataContext of Image and not on TabItem.
<Image Source="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=TabItem}}" Margin="10"/>
and similarly for TextBlock:
<TextBlock Text="{Binding Content, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=TabItem}}"
FontSize="32" Foreground="White" Margin="0,10,10,10"/>
specify the name of the style
<TabControl.Resources>
<Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
<Style.Setters>
and indicate style in TabItem
<TabItem Tag="Images/Plus.png" Content="Create New" Style="{StaticResource TabItemStyle}" />
Related
I have a custom TextBox control where the defaul value is the Tag string. When the TextBox is empty it shows a TextBlock on top with the Tag string with other color and centered. The control works on almost every scenario but I am having issues with one specifically. I have a TexBox that need to update a property when I type so I thought that adding the UpdateSourceTrigger=PropertyChanged will update the peroperty, but it doesn't work when I use the custom style, it works only on default so I thought that the issue is on the custom Style, but I am too new on xaml to figure out. Could someone please enlight me on what I am doing wrong?
<TextBox Grid.Column="2" Margin="5" Style="{StaticResource DefaultTextBox}" Tag="Sesión" Text="{Binding Sesion, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<!--Directorio TextBox-->
<Style x:Key="DefaultTextBox" TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Background="#ffffff" BorderBrush="#ffacacac" BorderThickness="1" CornerRadius="0">
<Grid>
<TextBox x:Name="TextBoxPersonalizado" Background="Transparent" BorderThickness="0" VerticalContentAlignment="Center" Text="{TemplateBinding Text}"/>
<TextBlock Foreground="#828282" HorizontalAlignment="Center" IsHitTestVisible="False" Text="{TemplateBinding Tag}" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=TextBoxPersonalizado}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Hidden"/>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TemplateBinding is for one direction only.
That beeing said, you need to use RelativeSource inside your template.
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"
Then you can use your customized TextBox like this.
<TextBox
x:Name="InputTextBox"
Grid.Column="0"
Width="100"
Margin="5"
Style="{StaticResource DefaultTextBox}"
Tag="Sesión" />
<TextBox Grid.Column="1" Text="{Binding ElementName=InputTextBox, Path=Text}" />
I have control template with a checkbox as this:
<Style x:Key="GeneralChkbxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid x:Name="RootElement">
<CheckBox ClickMode="Press" Content="{Binding Path=Name}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter
</Style>
I use this in a combobox and a listbox mentioning like this ItemContainerStyle="{StaticResource GeneralChkbxItemStyle .It works perfect when the datasource has a property named Name .
But I am wondering how can I use this template with other data source having class which does not have a name property . It might have a property name2, or name 3 etc depending on the datasource.
Any suggestions? Thanks.
In your template:
<CheckBox ClickMode="Press"
Content="{TemplateBinding Content}"
ContentTemplate="{templateBinding ContentTemplate}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />
Then in your view:
<ListBox DisplayMemberPath="Name"..../>
<!--OR-->
<ListBox DisplayMemberPath="Name2"..../>
<!--OR-->
......
You may use implicit data templates.
<DataTemplate DataType="MyApp:Person">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate DataType="MyApp:Booking">
<TextBlock Text="{Binding Id}" />
</DataTemplate>
<Style x:Key="GeneralChkbxItemStyle"
TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid x:Name="RootElement">
<CheckBox ClickMode="Press"
Content="{Binding .}"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TL;DR - I had a binding error. Tired eyes miss things.
I have implemented a multi-select CheckBox list using a ListBox as the container. Now, beside each checkbox in the list I want to display an image whose visbility is bound to a ViewModel property, but I'm having difficulty doing this.
My styles are:
<Grid.Resources>
<Style x:Key="ListBoxCheckStyle" TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ItemsPresenter HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsPanelTemplate x:Key="ListBoxCheckStyleItemsPanelTemplate">
<StackPanel />
</ItemsPanelTemplate>
<Style x:Key="ListBoxItemCheckStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<StackPanel Orientation="Horizontal">
<ChimeControls:CheckBox
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="0,0,10,0"
IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<Image
Width="16"
Height="16"
VerticalAlignment="Center"
Source="{StaticResource OccurredStatusTypeImageSource}"
Visibility="{Binding HasConsentCondition, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Collapsed}"
HorizontalAlignment="Right"
Margin="10,0,10,0" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
My Listbox is defined as:
<ListBox
x:Name="objectivesListBox"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Style="{StaticResource ListBoxCheckStyle}"
ItemsPanel="{StaticResource ListBoxCheckStyleItemsPanelTemplate}"
ItemContainerStyle="{StaticResource ListBoxItemCheckStyle}"
ItemsSource="{Binding ObjectivesList}"
DisplayMemberPath="mgt_plan_obj_name"
AttachedProperties:ListBoxSelectedItems.Items="{Binding SelectedObjectives, Mode=TwoWay}"
SelectionMode="Multiple"/>
My image never displays though, and the getter of the property the Visibility is bound to is never called. What am I missing?
As suggested by nemesv, I checked my output window again and there was my binding error.
I have a TreeView in WPF which I have bound to a collection of categories that itself contains a collection of categories and son on and so forth. Currently, I'm binding the collection successfully and having all of my category names appearing. However, I also have an IsExpanded property on my collection objects that when all set to true only expand the first TreeViewItem but no subsequent ones.
Does anyone know what may be wrong with my TreeView styles?
<HierarchicalDataTemplate x:Key="menuHierarchicalTemplate" ItemsSource="{Binding Path=SubCategories, Mode=TwoWay}" >
<Border x:Name="treeViewItemBorder"
CornerRadius="3"
MinWidth="125"
BorderBrush="Silver" Background="Transparent">
<StackPanel Orientation="Horizontal" >
<TextBlock Height="24" Padding="5" Text="{Binding Path=Name}" />
</StackPanel>
</Border>
</HierarchicalDataTemplate>
<Style x:Key="treeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<TreeViewItem IsExpanded="{Binding Path=IsExpanded, Mode=TwoWay}"
ItemsSource="{Binding Path=SubCategories}"
ItemTemplate="{StaticResource menuHierarchicalTemplate}" >
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal" >
<TextBlock Height="24" FontSize="12" Padding="5" Text="{Binding Path=Name}" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<TreeView Name="menuTreeView"
Background="Transparent"
BorderBrush="Transparent"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Margin="10"
ItemContainerStyle="{StaticResource treeViewItemStyle}">
</TreeView>
Thanks,
Xam
You are applying the "treeViewItemStyle" only to the first level of items in the TreeView. You have to set it as well as the ItemContainerStyle of the TreeViewItems. So, in your ControlTemplate, you'll need something like:
<ControlTemplate TargetType="TreeViewItem">
<TreeViewItem ItemContainerStyle="{StaticResource treeViewItemStyle}".../>
</ControlTemplate>
Better yet, you can just remove the "x:Key" attribute in your Style declaration. Doing so will automatically apply the style to all TreeViewItems.
SIDE NOTE:
I would suggest that instead of overriding the ControlTemplate like what you did above, just use property Setters in the Style instead. Something like:
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}"/>
<Setter Property="ItemsSource" Value="{Binding Path=SubCategories}"/>
<Setter Property="ItemTemplate" Value="{StaticResource menuHierarchicalTemplate}"/>
<Setter Property="Header">
<Setter.Value>
<StackPanel Orientation="Horizontal" >
<TextBlock Height="24" FontSize="12" Padding="5" Text="{Binding Path=Name}" />
</StackPanel>
</Setter.Value>
</Setter>
</Style>
It's quite unusual to use the same Control as part of the ControlTemplate of itself (i.e. using TreeViewItem in the ControlTemplate of a TreeViewItem).
I use this style for all my labels
<Style TargetType="Label" x:Key="LabelStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal" >
<TextBox Loaded="MyTextBlock_Loaded" x:Name="EditControl" Visibility="Collapsed" Text="{TemplateBinding Tag}" />
<Label Content="{TemplateBinding Content}" Grid.Column="1" Grid.Row="1">
</Label>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and my sample label
<Label Grid.Column="0" Grid.Row="0" Content="Photo" Style="{StaticResource LabelStyle}" Tag="{Binding fieldsCode.firstName, UpdateSourceTrigger=PropertyChanged}"/>
But I feel that TemplateBiding doesn't support update of property. How can solve this issue
Try this for two-way binding
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag, Mode=TwoWay}"
If you want a one-way binding from within the ControlTemplate to a property of its templated parent, use {TemplateBinding}. For all other scenarios use {Binding} instead:
<TextBox Loaded="MyTextBlock_Loaded" x:Name="EditControl" Visibility="Collapsed" Text="{Binding Tag, Mode=TwoWay}" />