I need to create a custom TextBox in WPF and the textbox will have some digit and the string "% Per Annum" like "55% Per Annum". The user should be able to alter only the digit from the textbox, I want to keep the string "% Per Annum" as uneditable. Please help me.
In WPF you can modify the template of a control to completely change the appearance while keeping the functionality. In your case you can modify the control template of a TextBox by adding some extra text inside the border of the control.
In Visual Studio add a TextBox to your XAML. Then in the Document Outline you can right click the TextBox and select Edit Template => Edit a Copy.... A Style for a TextBox is then added to your XAML including a copy of the ControlTemplate used by the default TextBox. You can then modify the template as you like.
The main part of the TextBox is the ScrollViewer inside the ListBoxChrome border. To get the result you desire you can wrap the ScrollViewer inside a Grid with two columns and then place a TextBlock with the text "% Per Annum" in the second column. You probably also want to right align the text in the TextBox and you can do that by default by setting HorizontalContentAlignment to Right in the Style of the TextBox.
Here is a complete sample XAML where I have added some comments to show where I made the edits:
<Window
x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#ABADB3" Offset="0.05"/>
<GradientStop Color="#E2E3EA" Offset="0.07"/>
<GradientStop Color="#E3E9EF" Offset="1"/>
</LinearGradientBrush>
<Style x:Key="PerAnnumTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<!-- New setter -->
<Setter Property="HorizontalContentAlignment" Value="Right"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<!-- ScrollViewer wrapped in a Grid -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<TextBlock Grid.Column="1" Margin="0,1"> % Per Annum</TextBlock>
</Grid>
</Themes:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="50" Style="{StaticResource PerAnnumTextBoxStyle}" Width="100" HorizontalAlignment="Left"/>
</StackPanel>
</Window>
The simplest and in my opionion better way is to put the text box inside a StackPanel
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=MyTextProperty}"/>
<Label Content="55% Per Annum" />
</StackPanel>
Related
I am trying to give my textblocks rounded borders. From what I've researched, I should embed a textblock within a border tag and then set the corner radius of the border. For me, it's having the effect of putting a border around the entire row. What am I doing wrong? I set the color of the border to blue to show what is happening. Ideally, I would change it to the same color as the background of the textblock to just give it seamless rounded corners.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="0" Margin="25" Grid.Column="1" Background="Blue"
BorderThickness="1" BorderBrush="Red" CornerRadius="30">
<TextBlock Margin="50" Padding="200,0,200,0"
FontSize="100"
FontWeight="Bold"
Background="Black"
Foreground="White"
VerticalAlignment="Center"
Text="bla bla bla"
HorizontalAlignment="Center">
</TextBlock>
</Border>
</Grid>
Look at the HorizontalAlignment / VerticalAlignment values for both the Grid and the Border. Set whatever is most appropriate for your requirements.
A tool such as Kaxaml is great for playing around with this sort of thing without having to build an entire application.
A better way to do this is to create a copy of the default style for TextBox and modify the border in the ControlTemplate. Here is a simple app that has the default TextBox style extracted and modified to round the corners.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<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" CornerRadius="5">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Margin="10" Style="{DynamicResource TextBoxStyle1}" Text="bla bla bla"></TextBox>
</StackPanel>
</Grid>
</Window>
If you want this style to apply to all textboxes in your app, you should move the style into a resource dictionary and remove x:Key="TextBoxStyle1" from the style definition. It would then apply to all TextBox by default and remove the need to set a Style for each one.
From what I understand, ListView has 2 themeing styles, one that it uses when you don't specify a View and one it uses when you do.
<HeaderedContentControl Header="No GridView" Margin="10">
<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>A</sys:String>
<sys:String>B</sys:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</HeaderedContentControl>
<HeaderedContentControl Header="GridView"
Margin="10">
<ListView>
<ListView.View>
<GridView>
<GridViewColumn Header="Content" />
</GridView>
</ListView.View>
<ListView.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>A</sys:String>
<sys:String>B</sys:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</HeaderedContentControl>
How do I style these? .. for example if I was making a custom theme?
I thought I would take a look at an existing theme, so I've downloaded the Luna theme from https://msdn.microsoft.com/en-us/library/aa972127(v=VS.90).aspx and added it as a resource. (I've added a button so you can see it is indeed using the luna theme)
But you'll notice that the Listview, other than the column header bit is the same. So it appears that the GridView styling in the luna theme isn't even used? I can go in and change the GridViewItemContainerStyleKey and it has no affect. It always appears to use the aero style
For reference, here is the GridView styling taken from the Luna theme :
<Style x:Key="{x:Static GridView.GridViewStyleKey}"
TargetType="{x:Type ListView}">
<Setter Property="Background"
Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush"
Value="{StaticResource ListBorder}"/>
<Setter Property="BorderThickness"
Value="1"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility"
Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll"
Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true">
<ScrollViewer Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}"
Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsGrouping"
Value="true">
<Setter Property="ScrollViewer.CanContentScroll"
Value="false"/>
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter TargetName="Bd"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Static GridView.GridViewItemContainerStyleKey}"
TargetType="{x:Type ListViewItem}">
<Setter Property="Background"
Value="Transparent"/>
<Setter Property="VerticalContentAlignment"
Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<GridViewRowPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="Bd"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected"
Value="true"/>
<Condition Property="Selector.IsSelectionActive"
Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="Bd"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Just dump the complete control template out using Expression Blend. The ones on MSDN aren't the real ones.
The header control items are GridiewColumnHeader controls. So you just target them as you normally would:
<Window.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="Red" />
</Style>
</Window.Resources>
This will turn your header red. If you want to dump out the real "runtime" template in Blend...
1) go into the XAML
2) update client XAML to:
<Grid>
<GridViewColumnHeader />
</Grid>
3) View | Objects & Timelines
4) You should see your window hierarchy there...
Window
Grid
GridViewColumnHeader
5) Select GridViewColumnHeader
6) Right click | Edit Template | Edit A Copy | OK
Then just modify / clean it up / refactor as you like.
Oooooooooooohhh... that is a ListViewItem. The GridView items are the column headers. What I did for that was have a "main" ListViewItem style and use a trigger that points to the ListView.View and if its x:Null, I assume its the normal view and set the template to my normal view template, otherwise set it to my GridView template. I do the same thing for having a themed and non themed version. So I actually have 4 templates.
I come to you because I got headaches about control styling for a few hours.
By defining a style to the usercontrol, it doesn't work !
My usercontrol declaration :
<uiComponent:NumericTextBox Text="{Binding myProperty}"/>
The style I want to apply to :
<Style TargetType="uiComponent:NumericTextBox">
<Setter Property="Background" Value="Black"/>
</Style>
Why it doesn't work with the Background property, although it works with the Visibility property !
I tried with TargetType=FrameworkElement, no effect....
My usercontrol is a numerictextbox which define its own style like this :
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:l="clr-namespace:LSX.Space.PropertyUI.NumericTextBox">
<SolidColorBrush x:Key="CustomTextBox_Background" Color="White" />
<SolidColorBrush x:Key="CustomTextBox_Foreground" Color="Black" />
<LinearGradientBrush x:Key="CustomTextBox_Border" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFABADB3" Offset="0.05" />
<GradientStop Color="#FFE2E3EA" Offset="0.07" />
<GradientStop Color="#FFE3E9EF" Offset="1" />
</LinearGradientBrush>
<Style x:Key="{x:Type l:NumericTextBox}" TargetType="{x:Type l:NumericTextBox}">
<Setter Property="Background" Value="{StaticResource CustomTextBox_Background}" />
<Setter Property="BorderBrush" Value="{StaticResource CustomTextBox_Border}" />
<Setter Property="Foreground" Value="{StaticResource CustomTextBox_Foreground}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:NumericTextBox}">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="LayoutGrid">
<ScrollViewer Margin="2" x:Name="PART_ContentHost" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--Message validation des erreurs-->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasText" Value="True" />
<Condition Property="Validation.HasError" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path= TextError}"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Image x:Name="ValidationIcon" DockPanel.Dock="Left" Stretch="None" Width="15" Height="15" Source="pack://application:,,,/LS.Net.Telcom.Space.PropertyUI;component/Images/validationError.png" />
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Many thanks for your help.
I just ran a quick test with your Styles, and everything is working properly. For WPF Styles to work properly, there are a couple of things you need to do however. The first is that your custom control needs to override the DefaultStyleKey in its static constructor:
public class NumericTextBox : TextBox
{
static NumericTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(NumericTextBox),
new FrameworkPropertyMetadata(typeof(NumericTextBox)));
}
...
}
The second is that your NumericTextBox's default Style needs to be defined at a specific location in your assembly for it to be picked up. The standard location is at Project\Themes\Generic.xaml.
If you're still struggling with how to create custom WPF controls and styling them, here is a great introductory CodeProject article.
bgcode's comment
TDefaultStyleKey, it is still implemented as you propose.
The second is that my NumericTextBox's style is implemented as a resourcedictionary into an other file, but I load it in constructor like that :
public NumericTextBox ()
: base()
{
ResourceDictionary res = Application.LoadComponent(new Uri("/MyAssemblyName;component/NumericTextBox/NumericTextBoxStyle.xaml", UriKind.RelativeOrAbsolute)) as ResourceDictionary;
if(res != null)
this.Resources = res;
}
I think that is a good way to do too, isn't it?
Abe Heidebrecht's response
No. Don't do that. If you want to define the default Style in a separate ResourceDictionary, do so. Just merge it into the generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyAssemblyName;component/NumericTextBox/NumericTextBoxStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
If you really don't want to have a generic.xaml, you can merge the dictionary into the App.Resources in your app.xaml. The reason why you'd prefer to put it in generic.xaml is that if at some point you put this control in a control's assembly, you will need it in generic.xaml, or WPF won't know where to find the default Style. It is better to get in the habit of doing it the right way.
I think I see what you're doing...
You're setting your Style in your ResourceDictionary and then setting the Style again somewhere else. So, your ResourceDictionary is loading the Background in your Style so it overrides what you're setting elsewhere.
This explains why Visibility works for you because that property is not being set in the Style in your ResourceDictionary.
You should set the Style as a StaticResource and then base any later styles off of that Style. This is basically what Sheridan suggested but you should reference the Style by a key name...
<Style x:Key="NumericBoxStyle" TargetType="{x:Type l:NumericTextBox}">
<Setter Property="Background" Value="{StaticResource CustomTextBox_Background}" />
<Setter Property="BorderBrush" Value="{StaticResource CustomTextBox_Border}" />
<Setter Property="Foreground" Value="{StaticResource CustomTextBox_Foreground}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:NumericTextBox}">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="LayoutGrid">
<ScrollViewer Margin="2" x:Name="PART_ContentHost" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--Message validation des erreurs-->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasText" Value="True" />
<Condition Property="Validation.HasError" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path= TextError}"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Image x:Name="ValidationIcon" DockPanel.Dock="Left" Stretch="None" Width="15" Height="15" Source="pack://application:,,,/LS.Net.Telcom.Space.PropertyUI;component/Images/validationError.png" />
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And adjust the style...
<Style TargetType="uiComponent:NumericTextBox" BaseOn="{StaticResource NumericBoxStyle}">
<Setter Property="Background" Value="Black"/>
</Style>
The style you define here
<Style TargetType="uiComponent:NumericTextBox">
<Setter Property="Background" Value="Black"/>
</Style>
gets overridden by the style defined in your ResourceDictionary
If you try :
<uiComponent:NumericTextBox Text="{Binding myProperty}">
<uiComponent:NumericTextBox.Style>
<Style TargetType="uiComponent:NumericTextBox" BasedOn="{StaticResource {x:Type uiComponent:NumericTextBox}}">
<Setter Property="Background" Value="Black"/>
</Style>
</uiComponent:NumericTextBox.Style>
</uiComponent:NumericTextBox>
.. your background should be set to black.
How about trying this:
<Style TargetType="uiComponent:NumericTextBox"
BasedOn="{StaticResource {x:Type l:NumericTextBox}}">
<Setter Property="Background" Value="Black"/>
</Style>
I'm not sure if your XML namespaces will match up, but the idea is to basically say to WPF, 'this style is based on the default style of this type'
I have a complex WPF application based on MVVM. I want to create an assistance mode for my application.So for example I am thinking that a customized tootip will open (on a textbox) when user opens the screen and remain opened until user puts some data into it. As user puts data,the focus will automatically shift to the next control and another tooltip for that control will open and this way the flow will go on.One thing, I want to code in XAML only..Any suggestion friends ???
I think it will be easier to modify the template of text box with some help from attached properties.
Make a class to hold helper attached properties. Let's call it Assistance and it will have two attached properties:
AssistanceTipContent of type object.
IsAssistanceActive of type bool.
Then the custom Style/Template for Text Box (based on default Aero theme):
<!--Add this xmlns definition to the root of the file-->
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
....
<!--Then in resources-->
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#ABADB3" Offset="0.05"/>
<GradientStop Color="#E2E3EA" Offset="0.07"/>
<GradientStop Color="#E3E9EF" Offset="1"/>
</LinearGradientBrush>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Microsoft_Windows_Themes:ListBoxChrome>
<Popup x:Name="AssistanceTip"
IsOpen="False"
AllowsTransparancy="True">
<!--TODO: Add Background/BorderBrush/BorderThicknes to this Border so it matches ToolTip style-->
<Border>
<ContentControl Content="{Binding Path=(Assistance.AssistanceTipContent), RelativeSource={RelativeSource TemplatedParent}}"/>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, IsKeyboardFocusWithin}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Text}" Value=""/>
<Condition Binding="{Binding Path=(Assistance.IsAssistanceActive), RelativeSource={RelativeSource Self}}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="AssistanceTip" Property="IsOpen" Value="True"/>
</MultiDataTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now your use will be something like:
<TextBox local:Assistance.AssistanceTipContent="Some text to help the user"
local:Assistance.IsAssistanceActive="{Binding IsAssistanceModeActive}"
..../>
This removes data triggers (to view model data) from styles and makes it quite generic approach.
[The change of focus is not handled here, I understand that you've accomplished that already.]
I try to change the Background property for my ListBoxItems using triggers in the ItemContainerStyle of my ListBox as follows:
<ListBox Height="100" HorizontalAlignment="Left" Margin="107,59,0,0" Name="listBox1" VerticalAlignment="Top" Width="239">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Lightblue"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="Red"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Items>
<ListBoxItem Content="First Item"/>
<ListBoxItem Content="SecondItem"/>
<ListBoxItem Content="Third Item"/>
</ListBox.Items>
</ListBox>
I would expect unselected items to have a light blue background, hovered items (i.e. when the mouse cursor is over them) to be yellow and selected items to be red.
For the unselected and hovered items this is working as expected, but the selected items still have their standard background color (i.e. blue, if the listbox has focus and light gray otherwise).
Is there anything I'm missing? Is this behaviour documented somewhere?
Thanks for any hint!
EDIT
I'm aware of the solution of overriding the default system colors (as described in Change selected and unfocused Listbox style to not be grayed out, thanks anyway for everyone posting this as an answer). However this is not what I want to do. I'm more interested in why my solution doesn't work.
I'm suspecting the standard ControlTemplate of ListItem to define it's own triggers which seem to take precendence over triggers defined by the style (perhaps someone could confirm this and point me to some resource where this behaviour is defined).
My solution for the meantime is to define a ControlTemplate for my ListItems like:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border" Padding="2" SnapsToDevicePixels="true" Background="LightBlue" Margin="0">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
A little bit of reflecting on the Aero-style offers us an explanation to why this simple trigger-setting doesn't work.
The ListBoxItem has a ControlTemplate with triggers that takes precedence over our trigger. At least this seems to be true for a MultiTrigger.
I´ve managed to override the simple trigger of Selected=true but for the multitrigger I had to make my own ControlTemplate.
This is the template from the Aero style that shows the problematic MultiTrigger:
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Bd" Value="{DynamicResource {x:Static HighlightBrush}}" Property="Background" />
<Setter Value="{DynamicResource {x:Static HighlightTextBrush}}" Property="Foreground" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Value="{DynamicResource {x:Static ControlBrush}}" Property="Background" />
<Setter Value="{DynamicResource {x:Static ControlTextBrush}}" Property="Foreground" />
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Value="{DynamicResource {x:Static GrayTextBrush}}" Property="Foreground" />
</Trigger>
</ControlTemplate.Triggers>
<Border Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
Hope it clears things up a little bit. I can't fathom why they´ve overcomplicated the style this much.
delete IsSelected trigger
And add to listbox:
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Red" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Red" />
</ListBox.Resources>
First brush for focused second for otherwise
Try adding this to your window resources -
<Window.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Red" />
</Window.Resources>
And remove the IsSelected Trigger from your code, it won't work because every system has its default highlight brush depending on your system theme.
You need to override the highlight brush in your code to make it work.
Try using Selector.IsSelected in your Trigger rather than IsSelected.