Styling the Xceed ColumnManagerCell - wpf

I'm interested in styling the column headers on an Xceed DataGrid. The goal is to make the background color grey, with a dark grey border around each header column cell. It seemed to me like the best way to do this was to style the ColumnManager:
<Style TargetType="{x:Type xcdg:ColumnManagerCell}">
<Setter Property="Template" Value="{StaticResource ColumnManagerCellTemplate}"/>
<Setter Property="BorderBrush" Value="#c5c5c5"/>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
</Style>
Using this template:
<ControlTemplate x:Key="ColumnManagerCellTemplate" TargetType="xcdg:ColumnManagerCell">
<Grid Background="LightGray" >
<xcdg:DataCell Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="LightGray"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
BorderBrush="DarkGray"
BorderThickness="2"/>
</Grid>
</ControlTemplate>
The background color shows up correctly, as does the content, but I cannot get a dark grey border to show up around each cell. (Or any color border at all.) What am I missing? Shouldn't the BorderBrush and BorderThickness properties control this? They seem to work on the rest of the cells in the grid, but not the ColumnManagerCells.

You should use a border instead of the grid and then hook up the template bindings for the border like this:
<Style TargetType="{x:Type xcdg:ColumnManagerCell}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="BorderBrush" Value="#c5c5c5"/>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I should mention that my default ControlTemplate for ColumnManagerCell is a ContentPresenter instead of DataCell like below:
<xcdg:DataCell Content="{TemplateBinding Content}" />
Are you sure your using the correct control template?

Related

Xaml switch between TextBlock and TextBox

I've noticed that TextBoxes are very slow and create performance issues when the Text is changed dynamically by code (I need to change the Text continuosly to 10-15 TextBoxes at the same time), so, as a workaround, I've created a custom control with a TextBlock and a TextBox:
The TextBlock is used in almost all time.
The TextBox is used only when I need to edit the Text inside the control with keyboard.
My solution is to change the template and use the TextBox when the control is focused:
(Value is a string Dependency Property)
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Value" Value="Val"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Value}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But when I click on the control nothing happens.
I think that the problem is that the "focus state" is passed to the internal TextBox, and the control loses the "focus state".
There is a better way to create a custom "TextBox" control like this, or a way to resolve this problem?
You don't need a custom control for this, that's just adding unnecessary overhead. What you're trying to create is still a TextBox, with all the usual behavior of a TextBox (focus etc). All you need to do is change the template to a TextBlock when it's not in focus:
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="Hello World" />
<TextBox Text="Goodbye World" />
</StackPanel>

Remove ToggleButton annoying background Mouse over style

I have simple ToggleButton and when IsChecked i want to change only the text.
I want all other properties like border and background will be Transparent but it seems that i still have this background style:
<ToggleButton x:Name="changeButBorderedBlinky" Content="EDIT" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
One thing that is often annoying is some visual aspects of the default WPF controls are coded in a way so as they are not configurable. The MouseOver Background is an example (scrollbar sizes is another... grrr!!!). You can solve this though by defining your own Template for the ToggleButton and eliminate that MouseOver trigger. Here is a simple example:
<ToggleButton x:Name="changeButBorderedBlinky" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="EDIT"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Focusable="False"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Also, in order to change a property in a trigger it has to be set in a style, not directly. That is why your Content doesn't change in your MouseOver Trigger. If you remove the property setting for it and
add it into the Style with a Setter, it will allow the trigger to change it.
One downside to all this is it overrides all the default template triggers so you won't see when the ToggleButton is checked anymore unless you add a trigger for "IsChecked" too. (and if you need to alter the Background in the trigger, move the Background Property to a Setter like I did for Content)
Hope that helps...
Sorry to revive an old thread, but (for someone struggling) the following worked for me. This can be in App.xaml file under Application.Resources tag or directly in the Window.Resources. I originally needed it for a UWP application, then had to adapt for WPF for a different project:
<Style TargetType="ToggleButton" x:Key="TransparentToggleButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="RootGrid" Background="Transparent">
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then just style your ToggleButton:
<ToggleButton Style="{StaticResource TransparentToggleButtonStyle}">
(whatever content you want to present)
</ToggleButton>
Hope this helps someone,

WPF TextBox Border Style Trigger IsFocused only works if has focus but not keyboard focus

I would like a nice little orange border around my Textbox whilst the user is typing in it (Has Focus).
I defined styles for the tiggers I think I need, but there is a strange behavior.
When the cursor is in the TextBox and the WPF app has focus, it has a blue border.
But while the cursor is focused and I click outside of the app (like in visual studio) it becomes orange.
I've tried overriding many triggers but to no avail.
This is what happens when I focus on the textbox but am focused on another app:
This is the textbox w/focus in the app:
And here is the code:
CTRL Xaml:
<TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Style="{StaticResource RegistrationTextbox}"
IsReadOnly="{Binding Path=IsFirstNameReadOnly}" Text="{Binding FirstName}" BorderThickness="0.99">
<b:Interaction.Triggers>
<b:EventTrigger EventName="GotFocus">
<b:InvokeCommandAction Command="{Binding GotFocusFirstNameCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</TextBox>
Styles:
<Style x:Key="RegistrationTextbox" TargetType="{x:Type TextBox}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="true">
<Setter Property="Background" Value="#f2f2f2"/>
<Setter Property="BorderBrush" Value="#f2f2f2"/>
<Setter Property="BorderThickness" Value="2"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="2"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="#FAA634"/>
<Setter Property="BorderThickness" Value="2"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="#F8B963"/>
<Setter Property="BorderThickness" Value="2"/>
</Trigger>
</Style.Triggers>
</Style>
Take a look at default TextBox style here: https://msdn.microsoft.com/en-us/library/cc645061%28v=vs.95%29.aspx
You will notice that in ControlTemplate there is this block:
<Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<Grid>
<Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/>
<Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
<ScrollViewer x:Name="ContentElement" Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False"/>
</Border>
</Grid>
</Border>
<Border x:Name="DisabledVisualElement" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Opacity="0" IsHitTestVisible="False"/>
<Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" Margin="1" Opacity="0" IsHitTestVisible="False"/>
You see here that only one Border's BorderBrush is bound to BorderBrush property of TextBox. When control goes to focused state - another border (FocusVisualElement) becomes visible and because it's positined later in visual tree - it overlays regular Border. Same is true when control goes to disabled or readonly state. So your style setters basically have no effect.
Now when your are switching to another app - TextBox does not consider it focused any more (note that it does not just use IsFocused property to determine that). So it hides FocusVisualElement and here you see border color applied by your trigger.
Long story short - control developers are not forced to bind to single BorderBrush property for every possible state. They could have provided something like FocusedBorderBrush property, but they did not - so you have to overwrite ControlTemplate of TextBox (you can use default template as provided by link above and overwrite some colors).

Where should I be defining and setting these styles

In the illustration below you can see a custom control that I'm currently creating with a view to learning as much as I can about the whole process of control creation.
Currently I'm trying to both simplify the xaml by effectively refactoring repetitive style elements out into a separate style and achieve a disabled look for images when the buttons in which they are situated are disabled.
In the xaml below you can see both the button style I've created and the data trigger for the image. In theory both are being applied to the second button on the left, but quite clearly they aren't being.
I think that the basic style definitions are correct but it may be that they are in the incorrect place. Can anyone advise as to what it is that I'm currently doing wrong.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewToLearn.WpfControls">
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}"
Value="False">
<Setter Property="Opacity"
Value="0.2"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Margin"
Value="4" />
</Style>
<Style TargetType="{x:Type local:VtlDataNavigator}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VtlDataNavigator}">
<StackPanel Orientation="Horizontal">
<Button BorderBrush="Transparent"
Background="Transparent"
BorderThickness="0">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_first24.png" />
</StackPanel>
</Button> <!-- This is the button that should be influenced by the style and trigger defined above, but clearly it isn't -->
<Button IsEnabled="False">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_previous24.png" />
</StackPanel>
</Button>
<TextBox Text="{Binding Path=RecordIndex,RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
IsReadOnly="True"
BorderThickness="0"
Margin="4" />
<TextBlock Text="of"
VerticalAlignment="Center"
Margin="4" />
<TextBlock Text="{Binding Path=RecordCount,RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
Margin="4" />
<Button BorderBrush="Transparent"
Background="Transparent"
BorderThickness="0">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_next24.png" />
</StackPanel>
</Button>
Your second button has IsEnabled="false"
That makes the difference.
But if you want the background to be the same for all buttons, enabled or not, you have to got in the triggers.
The best way to generate the default style and template with triggers is to put a dummy/test button in a window, right click on it, Edit Template/Edit a copy.
VS will generate much code. You 'll see inside the "full" template" of the button + the triggers.
Inside there is a trigger for different appearance when disabled :
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<!-- ... -->
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" TargetName="border" Value="#FFF4F4F4"/>
<Setter Property="BorderBrush" TargetName="border" Value="#FFADB2B5"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
It's that template you can take inspiration from to update your style (without trigger when disabled):
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Margin"
Value="4" />
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<!-- no trigger int he template -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notes regarding your code because it seems you are eager to learn :
Don't have to set Background, BorderThickness, BorderBrush for every button, it is already done in your Button style
The StackPanel around every Image is the same and can be put inside the template around the ContentPresenter tag
If VtlDataNavigator is a Usercontrol, you can put all the content of <ControlTemplate TargetType="{x:Type local:VtlDataNavigator}"> inside the <UserControl> tag.
It makes the control more reusable (don't have to provide the template in every Window for the control)
Regards

How do I set the height of a wpf slider control's thumb

I want to put a slider in a datagrid cell and the row has a height of 20, so i'd like to make the height of the thumb of the slider smaller than that. I set the height of the slider itself, but the thumb appears to be cut off (i.e. it doesn't scale down to the height that I specify in the slider.height property). I don't want to have to override the entire control template of the slider control to do this. There's got to be some way of setting a property or something like that.
Edit: Even when I create a custom slider style which includes the custom thumb style with the sizes I want, it still doesn't size right.
Any ideas?
<Slider.LayoutTransform>
<ScaleTransform ScaleY="0.9" CenterX="15" CenterY="15"/>
</Slider.LayoutTransform>
Not very sexy, but it works like a charm when combined whith the Slider.Height/Slider.Width properties !
Set thumb style:
<Style x:Key="SliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<!--<Ellipse
Name="Ellipse"
Fill="Yellow"
Stroke="Yellow"
Height="10"
Width="{Binding Path=ThumbWidth, RelativeSource={RelativeSource TemplatedParent}}"
StrokeThickness="1" />-->
<Rectangle
Fill="Azure"
Stroke="Azure"
Height="7"
Width="{Binding Path=ThumbWidth, RelativeSource={RelativeSource TemplatedParent}}"
StrokeThickness="1"
Margin="0.1,.1,.1,.1"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then use this style slider custom control
<Style TargetType="{x:Type local:NvSliderControl}">
<Setter Property="Orientation" Value="Vertical" />
<Setter Property="Height" Value="50"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NvSliderControl}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Track x:Name="PART_Track" >
<Track.Thumb>
<Thumb Style="{StaticResource SliderThumbStyle}">
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources