Applying a Custom Template for TextBox Header - c#

I am developing a windows phone app and my requirements include to use a specific color theme and not use the default theme (Light/Dark/etc.) of the phone.
I'm stuck at formatting/templating the headers of textboxes. The following code in the app.xaml is not working:
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="{Binding}" Foreground="Black"/>
</DataTemplate>
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderTemplate}"/>
</Style>
Is there either a way just to configure the theme used or a way to implement the template for the headers?

If you need to implement a Template on a Page
<Page.Resources>
<Style TargetType="TextBox">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" Foreground="Red" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel>
<TextBox x:Name="TextBox" Width="300" Height="80"
Margin="20" Header="Headline"/>
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"/>
</StackPanel>
or if you want the Style to apply to certain TextBox give it a Key
<Style TargetType="TextBox" x:Key="MyTextBoxStyle">
and apply to relevant TextBox
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"
Style="{StaticResource MyTextBoxStyle}"/>}"/>
Hope that helps

It is really strange I tested the following:
<Application.Resources>
<Style TargetType="TextBox" >
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Red" Text="testing"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="DT1">
<TextBlock Foreground="Green" Text="testing"/>
</DataTemplate>
<Style TargetType="TextBox" x:Key="TextBoxStyle2">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource DT1}"/>
</Style>
</Application.Resources>
and in the mainpage
<Grid>
<TextBox Text="testing"/>
<TextBox Margin="0,100,0,0" Style="{StaticResource TextBoxStyle2}" Text="testing"/>
</Grid>
And it works, so I think the content from the binding is empty and appears not be working.

Related

How can I add something to my custom listbox?

I made a custom listbox but when I push the button show every language nothing is showing. How can I fix this. When I delete the listbox style it just works fine. It's all in C#.
I hope you can help me.
greetings
Elias
<ListBox x:Name="lsbResultaatTaal"
Foreground="Black"
FontSize="15"
Grid.Row="1"
Margin="528,56,0,0"
Height="450"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="233">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{d:SampleData ItemCount=5}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<Border Width="230" Height="450"
CornerRadius="9"
BorderThickness="1"
BorderBrush="Black"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
You can set style in resources
<Window.Resources>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray" />
<!--
Why you choose same background color when hover listbox
Maybe same color your background and foreground
-->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
OR
Can you try below changes:
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding YourProp}" />

How do I change a controls background on my UserControl when the item is selected

So I have this ListView which has a DataTemplate of my UserContol because I wanted a custom design for my ListView and it looks like this
<ListView x:Name="LeftMenuListView"
ItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem}"
BorderThickness="0"
Width="255">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<local:MenuItemControl/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Super simple, now when an Item is selected the entire thing changes color
which I want it looks great imo
<Style TargetType="ListViewItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
Name="Border"
BorderThickness="0">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background"
Value="#444444"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But there is a border inside my usercontrol thats 10px wide with the name SmallBorder.
I want to change the color of that to green when the item is selected but I have no idea how to access that property
My UserControl
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder"/>
</Grid>
So how do I change the color of SmallBorder when an item is selected and then when it's not selected it turns transparent?
The ViewModel, which is the DataContext of you usercontrol, should expose a property like IsSelected, then you can add an style with a DataTrigger that reacts to a change in this property.
EDIT:
Declare an style for the border itself an access it as an StaticResource:
It could be placed in a ResourceDictionary, within YourUserControl.Resources or inline with the Border control declaration:
<Style TargetType={x:Type Border} x:Key=SelectedBorderStyle>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="BorderBrush" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
And then your UserControl would be:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
Style={StaticResource SelectedBorderStyle}
HorizontalAlignment="Left"/>
</Grid>
Note that now you don't need to set the name for the Border.
A Border is invisible unless there is something in it, but you could replace the Border with a Grid and use a Style with a DataTrigger that binds to the IsSelected property:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Grid Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
</Grid>

Unable to resize StackPanel when IDataErrorInfo is triggered

When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.

wpf ResourceDictionary not applied to ContentControl

I have a wpf application, here i've made a contentcontroller that has a label and a button. this will be used as an overlay when something is loading.
the .cs file
namespace VLC.WPF.Controls
{
public class LoadingOverlay : ContentControl
{
}
}
the .xaml file
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VLC.WPF.Controls">
<Style TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
all of this will be used like this
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<controls:LoadingOverlay.Resources>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</controls:LoadingOverlay.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>
in various usercontrols, it's functioning correctly but the styly doesn't appear to load.
What could be wrong here? the code looks alright so i think it should be loading but it isn't.
in your style try adding the TargetType to your ControlTemplate like this
<ControlTemplate TargetType="local:LoadingOverlay">
What I don't understand is why are you setting the styling in the UserControl Resources and not using Keys to reference styles in your ResourceDictionary. It would keep your overall code much cleaner and you wouldn't have to change each control if you have to make a minor change later... for example:
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<ContentPresenter Content="{Binding OverlayContent}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And when you call the control in your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
and if you find you need to alter the style for another page, instead of doing an inline style for the control - after the originally defined style try this:
<Style x:Key="overlayTwo" TargetType="local:LoadingOverlay" BasedOn="{StaticResource overlayOne}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
This style uses all the information you have already defined and adds another data trigger, or you could override what is there, change other elements in style such the font size or colors.
Then, you just have to use this key when defining your control
<local:LoadingOverlay Style="{DynamicResource overlayTwo}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</local:LoadingOverlay>
Sorry for the long winded answer, but I see this being a potential problem if you have a lot of these controls on different pages and by not keeping all of your styling in the ResourceDictionary
P.S. If your content is going to be the same that could also be part of the style like below
<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LoadingOverlay">
<Grid>
<Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
And then you only need on your page
<local:LoadingOverlay Style="{DynamicResource overlayOne}"/>
You actually override the style within the LoadingOverlay resources.
Replace <Style TargetType="controls:LoadingOverlay"> by the following <Style TargetType="{x:Type controls:LoadingOverlay}" BasedOn="{StaticResource {x:Type controls:LoadingOverlay}}"> and voila!
The resource must be defined before the UI element that will be using it. If a control uses a style resource, that style must be higher in the visual tree.
Move the style to the UserControl resources
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="controls:LoadingOverlay">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<controls:LoadingOverlay>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
<Button x:Name="Cancel" Content="Annuleren"/>
</StackPanel>
</controls:LoadingOverlay>

How to use style for GroupBox header?

I have lost of GroupBox in my form that their header text must be Bold. I know how to do it for a single GroupBox:
<GroupBox>
<GroupBox.Header>
<TextBlock Text="HEADER TEXT" FontWeight="Bold"/>
</GroupBox.Header>
</GroupBox>
But I'm interested to know how to do it with Styles. Here is what I have tried:
<Style TargetType="GroupBox">
<Setter Property="BorderBrush" Value="{StaticResource lightBlueBrush}"/>
<Setter Property="Margin" Value="25,1,5,5"/>
//<Setter ??
</Style>
I have tried <Setter Property="HeaderTemplate" Value={StaticResource myTemp}> Which myTemp is a simple DataTemplate But VS suddenly closed! I'm not sure if I'm in the correct way of doing it, so anyone could help me?
EDIT: Please test your idea before posting it as an answer!
Did you try the following?
<Style TargetType="GroupBox">
<Setter Property="BorderBrush" Value="{StaticResource lightBlueBrush}"/>
<Setter Property="Margin" Value="25,1,5,5"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Usage:
<GroupBox Header="Title" />
A groupboxs headerTemplate is a type of DataTemplate. so you should provide a datatemplate object insteed of style or template.
try below one.
<Window.Resources>
<DataTemplate x:Key="DataTemplate1">
<TextBlock Text="Test Templated Header"/>
</DataTemplate>
</Window.Resources>
<Grid>
<GroupBox Header="Test Header" HeaderTemplate="{StaticResource DataTemplate1}">
<Border BorderBrush="Red" Margin="10">
<TextBlock Text="Hello"/>
</Border>
</GroupBox>
</Grid>

Categories