I have a Style for an Expander. I want the Foreground property of the Header to be different from the Content.
<Style TargetType="Expander">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<StackPanel>
<ContentControl Content="{TemplateBinding Header}" Foreground="{TemplateBinding Foreground}"/>
<ContentControl Content="{TemplateBinding Content}" Foreground="Blue" TextBlock.Foreground="Blue"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Expander>
<Expander.Header>
<TextBlock Text="Header"/>
</Expander.Header>
<Expander.Content>
<TextBlock Text="Content"/>
</Expander.Content>
</Expander>
However, once the Style is applied, both the Header and the Content come back as Red i.e. the Expander style Foreground colour.
How can I get the Expander style to contain multiple Foreground colours.
First, in template is better to use the ContentPresenter, instead of ContentControl, which is a common practice. Quote reply Nir (Question: What's the difference between ContentControl and ContentPresenter?):
ContentControl is a base class for controls that contain other elements and have a Content-property (for example, Button).
ContentPresenter is used inside control templates to display content.
ContentControl, when used directly (it's supposed to be used as a base class), has a control template that uses ContentPresenter to display it's content.
Inside ControlTemplate use ContentPresenter;
Outside of ControlTemplate (including DataTemplate and outside templates) try not to use any of them, if you need to, you must prefer ContentPresenter;
Subclass ContentControl if you are creating a custom "lookless" control that host content and you can't get the same result by changing an existing control's template (that should be extremely rare).
Second, the type of construction:
<Expander Header="MyHeader">
<Expander.Content>
<TextBlock Text="Content"/>
</Expander.Content>
</Expander>
You automatically overwrites your the template (style), so the color is the same everywhere, because Red is set, taken from the Style setter.
So, a slightly modified example:
<Style TargetType="{x:Type Expander}">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<StackPanel>
<Border BorderThickness="{TemplateBinding BorderThickness}" TextBlock.Foreground="{TemplateBinding Foreground}">
<ContentPresenter Content="{TemplateBinding Header}" />
</Border>
<Border Name="Content" BorderThickness="{TemplateBinding BorderThickness}" TextBlock.Foreground="Blue">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Grid>
<!-- Work -->
<Expander Header="MyHeader" Content="MyContent" />
<!-- Not work -->
<!--<Expander Header="MyHeader">
<Expander.Content>
<TextBlock Text="Content"/>
</Expander.Content>
</Expander>-->
</Grid>
To study the work style, you can take a predefined style (such as MSDN), and change it from there.
Note: It is better to design a universal template to the content, because if you set the content other than TextBlock, color for TextBlock will be useless. Perhaps it is better to set the color in style for the TextBlock.
Related
Hey I'm designing a new style for a textbox in my WPF application using XAML codes. The textbox is a combination of textbox and textblock, I used the textblock to show name of the textbox when the text is null, and disappears when the text is filled, but there is a problem when I run the app and fill something in the textbox it seems that it's working properly but in the backend when I want to access the textbox Text it's null even though it's filled!!!!
Am I doing something wrong from the base or I missed something to do.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TextBox}"
x:Key="TextBoxTheme">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="10"
Background="#353340"
Width="200"
Height="40">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{TemplateBinding Property=Text}"
BorderThickness="0"
Background="Transparent"
VerticalAlignment="Center"
Padding="5"
Foreground="#CFCFCF"
x:Name="textBox"/>
<TextBlock IsHitTestVisible="False"
Text="{TemplateBinding Name}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10, 0, 0, 0"
FontSize="11"
Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=textBox}" 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>
</ResourceDictionary>
Instead of giving the TextBox an area to display its contents, you have overlapped it on top with another TextBox.
To display its content, the TextBox looks in the Template for ScrollViewer x:Name="PART_ContentHost".
Try a Template like this:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<TextBlock x:Name="PART_TextBlock" Text="{TemplateBinding Name}" Visibility="Collapsed"/>
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Text"
Value="{x:Static sys:String.Empty}">
<Setter TargetName="PART_TextBlock" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
Found this on the YouTube video comments where this question code comes from. In the template xaml file do the following:
Repalce This:
Text="{TemplateBinding Text}"
With This:
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text, UpdateSourceTrigger=PropertyChanged}"
I was able to capture text from the TextChanged event after this change.
If you check the documentation for TemplateBinding you'll see it's just syntactic sugar for a one-way RelativeSource binding to the templated parent, so all you need to do is change your TextBox binding to make it two-way:
Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Also, I disagree with the comment above about this not being a good idea, one of the whole purposes of WPF's templating system is to make it possible to template existing controls e.g. for redistribution of libraries etc. That said, I don't think Name is the best property to use for your hint text, if for no other reason than the fact that it doesn't allow spaces. A much better solution would be to use an attached property. For a quick-and-dirty solution there's also the Tag property, which you're free to use for whatever you want.
I want to change my WPF & C# code to telerik. Before change i have HeaderContentControl with some Workspaces
My XAML code
<HeaderedContentControl
Content="{Binding Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
Style="{StaticResource MainHCCStyle}"
/>
My Resources
<Style x:Key="MainHCCStyle" TargetType="{x:Type HeaderedContentControl}>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}>
<DockPanel>
<ContentPresenter
ContentSource="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
Margin="4"
/>
</DataTemplate>
After modify code to Telerik my code looks like
My XAML code
<telerik:RadTabbedWindow
Content="{Binding Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
telerik:StyleManager.Theme="Office2016"
Style="{StaticResource MainHCCStyle}"
/>
My Resources
<Style x:Key="MainHCCStyle" TargetType="{x:Type telerik:RadTabbedWindow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type telerik:RadTabbedWindow}">
<DockPanel>
<ContentPresenter
ContentSource="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
Margin="4"
/>
</DataTemplate>
Workspaces wors ok, but Telerik theme doesn't work ( telerik:StyleManager.Theme="Office2016"). Styles only activate if I delete them Style="{StaticResource MainHCCStyle}", however then workspaces doesn't work
The custom Style that targets RadTabbedWindow is overriding its ControlTemplate (via the Template property). This means that the default look and feel of the control is replaced with the Dock panel defined in the Style.
To make this work, set the ContentTemplate of RadTabbedWindow, instead of its Template property.
I'm using the TextBox below, which in order to apply a DropShadowEffect on its text, uses a ControlTemplate. I managed to get the TextWrapping to work, but once the TextBox fills up, it's content goes out of view. How do I replicate the Auto scrolling to the bottom feature of a native TextBox?
<TextBox TextWrapping="Wrap"
Foreground="LimeGreen"
Background="Black"
Margin="10,40,10,40"
FontSize="40"
HorizontalAlignment="Stretch"
x:Name="Inp"
FontFamily="Courier New"
CaretBrush='LimeGreen'>
<TextBox.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid x:Name="RootElement">
<ScrollViewer>
<ContentPresenter Content="{TemplateBinding Text}">
<ContentPresenter.Effect>
<DropShadowEffect ShadowDepth="4"
Direction="330"
Color="LimeGreen"
Opacity="1"
BlurRadius="5" />
</ContentPresenter.Effect>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property='TextWrapping'
Value='Wrap' />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Resources>
</TextBox>
This solution is a bit different that what you might expect. I think using the ContentPresenter is the wrong way because in the end you still want the functionality of the TextBox. So my solution focuses on getting rid of the border and focus indicator that mess up the drop shadow effect:
<TextBox x:Name="Inp"
Height="100"
HorizontalAlignment="Stretch"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CaretBrush="LimeGreen"
FontFamily="Courier New"
FontSize="40"
Foreground="LimeGreen"
TextWrapping="Wrap">
<TextBox.Effect>
<DropShadowEffect BlurRadius="5"
Direction="330"
Opacity="1"
ShadowDepth="4"
Color="LimeGreen" />
</TextBox.Effect>
<TextBox.FocusVisualStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate/>
</Setter.Value>
</Setter>
</Style>
</TextBox.FocusVisualStyle>
</TextBox>
I set the Background, BorderBrush to be transparent (=> no shadow). I removed the ContentPresenter; it's a 'regular textbox now. And to remove the focus border I set the FocusVisualStyle to an empty Template.
I am getting some strange behavior when I follow the steps provided by other SO answers to how to style tab item headers.
With
<Style TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<buttons:MyButtonControl Content="{TemplateBinding Content}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
And a tab control as follows
<TabControl>
<TabItem Header="Buttons">
<local:Buttons />
</TabItem>
<TabItem Header="Labels">
<local:Labels />
</TabItem>
</TabControl>
I get a tab control that looks like this
How do I get the style to apply to all tab headers? How do I remove the default tab header style around my datatemplate?
EDIT
If I style the Template rather than the header template the content stops showing up but at least the border goes away on the header that works.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<buttons:MyButtonControl Content="{TemplateBinding Content}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The missing part appears to have been a ContentPresenter with the ContentSource property set to Header.
(Also using a button in the header prevents the tab from being clicked on because the button eats the click event.)
This code displays correctly.
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border>
<ContentPresenter ContentSource="Header">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I would like to create a style that could be applied to any ContentControl which would take the ToolTip and add an image to the ContentControl and apply the tool tip text from the object to the image. I have about a hundred of these that need to be done (in various projects) so being able to create a style would save a lot of typing.
What I am trying to recreate is this (ToolTip text is on the blue 'i' and not the 'Reload Employee Data':
which is accomplished via the following:
<StackPanel Orientation="Horizontal">
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0">
</CheckBox>
<Image Source="/DelphiaLibrary;Component/Resources/info.ico"
ToolTip="Check if you want to re-upload ..."/>
</StackPanel>
What I am trying to avoid is creating a new stack panel each time I want to add the blue 'i' with the tool tip text on the 'i' and not on the text of the object.
I was able to create the following that works for a Label:
<!-- Works for just Label -->
<Style x:Key="LabelToolTipStyle"
TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}" />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I can call this simply by adding the style to the label like so:
<Label Content="First Text" Style="{StaticResource LabelToolTipStyle}" ToolTip="Label with LabelToolTipStyle" />
I then tried to make this more generalized by creating a style targeting ContentControl but obviously doesn't work because this overrides the entire template (in the case of CheckBox control, the checkbox is missing):
<!-- Works on Label but not CheckBox -->
<Style x:Key="ContentToolTipStyle"
TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}" />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is there a way that I could create a style for ContentControls that would allow me to ADD to the template without redefining the entire template? If it cannot be done to ContentControl I wouldn't be opposed to creating a separate style for each control type but would like to avoid redefining the entire template to do so.
You are almost there. You need to create a custom control template for a ContentControl:
<Style x:Key="ToolTipWrapper" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<StackPanel Orientation="Horizontal">
<StackPanel.ToolTip>
<ToolTip Visibility="Hidden" />
</StackPanel.ToolTip>
<ContentPresenter />
<Image Source="info.ico" ToolTip="{TemplateBinding ToolTip}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then wrap your elements in a ContentControl and apply the style:
<ContentControl Style="{StaticResource ToolTipWrapper}" ToolTip="Hello world">
<CheckBox Content="I am a check box" />
</ContentControl>
What you can't do is to automatically apply the custom style to all "content" controls: you will always need the extra ContentControl wrapped around each element you want to style in this way.