WPF: Slider Thumb Outside the SliderControl - c#

I need to extend a slider thumb to stick out of its control. Is that possible then how? If not how can i achieve this? Please Help.
For e.g My slider's height is 50 but the thumb must start -50px outside the control and have 100 height.
Here yellow is the slider control, red is the thumb now I need the thumb to extend add the orange part to the same thumb.
Thanks

If you can build a UI using WPF controls, then you can define a new ControlTemplate... it really is no different. Here is how... always start by implementing the default ControlTemplate so that your object initially looks 'normal'. Then simply locate the part you want to change... and change it:
The trick with this one is that the Thumb does not stick out of the control, instead the whole control is enlarged. Now the default ControlTemplate is so large that I'm not going to add all of the XAML here. Start with the default one that #VimalCK kindly added a link to (don't forget to include the Resources) and then add these changes (hopefully I've remembered all that I changed:
<Style x:Key="SliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="14" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Grid>
<Ellipse x:Name="Ellipse" StrokeThickness="1" Height="14"
VerticalAlignment="Bottom">
... <!--Use default XAML here-->
</Ellipse>
<Rectangle Height="200" Width="2" Stroke="Red" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then inside the HorizontalSlider ControlTemplate, change the TrackBackground Border definition to this:
<Border x:Name="TrackBackground" VerticalAlignment="Bottom" Margin="0,0,0,5"
CornerRadius="2" Height="4" Grid.Row="1" BorderThickness="1">
... <!--Use default XAML here-->
</Border>
Then use it with a Height like this:
<Slider Height="210" Maximum="100" Minimum="0" TickPlacement="BottomRight"
VerticalAlignment="Bottom" />
I think I documented all the changes that I made... if not, you might need to set a Height, or a VerticalAlignment to Bottom on something... either way, just experiment until you get what you want. Exploring how the default ControlTemplates have been defined is a great way to learn WPF.

The WPF controls provided by Microsoft has a default style and template which is available in MSDN and you can modify this based on your requirements. For Slider control Style and Template please visit below link
http://msdn.microsoft.com/en-us/library/ms753256(v=vs.110).aspx

Wrap thumb by Canvas Control and set ClipToBOunds= "False" like this
<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}">
<Canvas>
<Border Width="16" Height="16" Canvas.Top="-3" ClipToBounds="False" Background="Black" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

WPF how to attach different style to last child

I've got a WrapPanel containing multiple Buttons.
All buttons have the same base style to define their basic appearance.
Every button has a visible border at the right side. But I want to use styles to remove the border of the last button.
I think its quite simple. WPF is new to me, so I want to understand it.
The solutions I find on the internet are for different cases. That solutions are all concerning ListBox or ItemContainer to style some list items by index.
I don't want to just add another style key to the last Button, because that's not dynamic, and the WrapPanel is dynamically populated with Buttons depending on the state of the application.
This is my code:
<Window.Resources>
<Style x:Key="lastTabStyle" TargetType="Button">
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style x:Key="tabButton" TargetType="Button">
<Setter Property="Background" Value="#FF21588B" />
<Setter Property="BorderThickness" Value="0 0 1 0" />
<Setter Property="Foreground" Value="#fff" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" Padding="20 10 20 10">
<ContentPresenter HorizontalAlignment="left" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF266095" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="tabButtonSelected" TargetType="Button">
<Setter Property="Background" Value="#FF3474B0" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" Padding="10 8">
<ContentPresenter HorizontalAlignment="left" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And the WrapPanel:
<WrapPanel VerticalAlignment="Bottom" x:Name="topTabs">
<Button Style="{StaticResource tabButton}">Button 1</Button>
<Button Style="{StaticResource tabButton}">Button 2</Button>
<Button Style="{StaticResource tabButton}">Button 3</Button>
</WrapPanel>
...But I want to use styles to remove the border of the last button.
Then the define another style and apply this to the last Button or simply set ("override") the BorderThickness property of the last Button:
<WrapPanel VerticalAlignment="Bottom" x:Name="topTabs">
<Button Style="{StaticResource tabButton}">Button 1</Button>
<Button Style="{StaticResource tabButton}">Button 2</Button>
<Button Style="{StaticResource tabButton}" BorderThickness="0">Button 3</Button>
</WrapPanel>
Local values take precedence over values set by styles: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence

UWP CustomControl Styles don't inherit from default styles

I'm creating a custom control (not UserControl) and I put my default style in generic.xaml. Since I'm basing my control on CheckBox, and I'm not really doing anything interesting other than adding some extra logic on the backend and maybe overriding a single property I would like to base my styles on the default styles.
Previously, I would be able to do something like
<Style TargetType="local:MyCheckBox" BasedOn="CheckBox">
<Setter Property="..." Value="..." />
</Style>
And this would use the default style and override my single property. Is this possible in UWP apps or do I need to copy the entire built-in style and change my single property?
My class is defined like this:
public class MyCheckBox : CheckBox
{
public MyCheckBox()
{
this.DefaultStyleKey = typeof(MyCheckBox);
}
// etc.
}
<Style TargetType="local:MyCheckBox" BasedOn="CheckBox">
<Setter Property="..." Value="..." />
</Style>
And this would use the default style and override my single property. Is this possible in UWP apps or do I need to copy the entire built-in style and change my single property?
By my side, if I use BasedOn="CheckBox" and place a MyCheckBox in the MainPage, this error will occur:
The name "MyCheckBox" does not exist in the namespace "xxxx".
Invalid value for property 'BasedOn':...
Cannot assign text value 'CheckBox' into property 'BasedOn' of type 'Style'.
If you want to use BasedOn style here, you can refer to Use based-on styles. According to this doc, you will need to use StaticResource here.
But I don't think here only using BasedOn style can solve the problem. Yes you are right, CustomControl style doesn't inherit from default styles, as you can see, the generic.xaml includes a default style, in this style there are only a ControlTemplate and a Border, it's empty.
Since I'm basing my control on CheckBox, and I'm not really doing anything interesting other than adding some extra logic on the backend and maybe overriding a single property I would like to base my styles on the default styles.
If I understand your request correctly, since the customcontrol's template is fast empty, so you are also right, you will need to copy the entire built-in style. For example, you can modify the template the same as the CheckBox's ControlTemplate:
<Style x:Key="CheckBoxStyle" TargetType="CheckBox">
<Setter Property="Background" Value="Blue" />
<Setter Property="Foreground" Value="Red" />
<Setter Property="Padding" Value="8,5,0,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
</Style>
<Style TargetType="local:MyCheckBox" BasedOn="{StaticResource CheckBoxStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyCheckBox">
<Grid BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Height="32" VerticalAlignment="Top">
<Rectangle x:Name="NormalRectangle" Fill="Transparent" Height="20" Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}" StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}" UseLayoutRounding="False" Width="20" />
<FontIcon x:Name="CheckGlyph" Foreground="{ThemeResource SystemControlHighlightAltChromeWhiteBrush}" FontSize="20" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="" Opacity="0" />
</Grid>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" Grid.Column="1" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" TextWrapping="Wrap" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But I think you can also modify the template of your customcontrol like this:
<Style x:Key="CheckBoxStyle1" TargetType="CheckBox">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style TargetType="local:MyCheckBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyCheckBox">
<CheckBox Content="222" Style="{StaticResource CheckBoxStyle1}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This will make your CustomControl getting the default style of CheckBox, so which single property do you want to change?

Modify button style when receiving focus via <tab> but not when clicked on

What I want to do
When tabbing through the user interface most WPF controls display a dashed border when they receive keyboard focus. They do not display this border when they are clicked on with the mouse.
I have a button with a custom control template and I want the same behavior as above however I don't just want to add a border but I want to modify the appearance of the button itself.
What I tried
Customizing the FocusVisualStyle. This doesn't give me enough flexibility because the template set by the FocusVisualStyle is added on-top of the button. As far as I am aware this can not be used to modify (style, animate,...) the button itself in any way.
Styling the button using Triggers with the IsFocused and/or IsKeyboardFocused properties as well as EventTriggers with the Got/LostFocus and/or Got/LostKeyboardFocus events. That doesn't work either because all of those seem to get triggered when I click on the button too.
Example code
<StackPanel VerticalAlignment="Center" Width="150">
<StackPanel.Resources>
<ControlTemplate x:Key="CustomButtonTemplate" TargetType="Button">
<!--A simple black border with a content presenter-->
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="2">
<ContentPresenter x:Name="Presenter" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" />
</Border>
<ControlTemplate.Triggers>
<!--When receiving keyboard focus modify the button text-->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Presenter" Property="Content" Value="I have keyboard focus" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="CustomFocusVisualStyle" TargetType="Control">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<!--Display a red border-->
<Border BorderThickness="1" CornerRadius="2" BorderBrush="Red" Margin="-1" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<Button Content="I am a normal button" Margin="5" />
<Button Content="I am a custom button" Margin="5"
Template="{StaticResource CustomButtonTemplate}"
FocusVisualStyle="{StaticResource CustomFocusVisualStyle}" />
</StackPanel>
Note how the custom red focus border shows up only when you tab between the two buttons but not when you click the buttons. The custom button text however gets modified in either case.
How can I achieve this?
Ok, after countless hours, I finally found a solution that works for my scenario. I hope it works for yours as well.
Forget FocusVisualStyle, it is junk. I'm using a MultiTrigger that is tied to IsKeyboardFocused=True and IsMouseCaptured=False.
Here is what my style looks like now:
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="True"/>
<Condition Property="IsMouseCaptured" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="Green" />
<Setter Property="BorderThickness" Value="2" />
</MultiTrigger>
</Style.Triggers>
This gives me a green ring around my button only when tabbed to, not when focused via mouse.

How to modify WPF menu drop down visual?

I have a WPF menu:
XAML:
<Style x:Key="{x:Type ContextMenu}" TargetType="{x:Type ContextMenu}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border Background="#FF171616" CornerRadius="5" BorderBrush="DarkGray" BorderThickness="5" Opacity="0.0">
<StackPanel ClipToBounds="True" Orientation="Vertical" IsItemsHost="True" Margin="5,4,5,4"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Am I using the correct x:Type ContextMenu to alter the drop down visualization? The menu item visual is altered because I've manually changed the style. But it is the context drop down on which I want to apply visuals.
How can I modify the context drop down itself?
Here is a paint sample of what I'm after:
To modify style for menu, you need to override Menu style.
Like below:
<Style TargetType="{x:Type Menu}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="#FF171616" />
</Style>
Edit: you can actually modify the whole template also, if you like. But I think these properties should get you the visualization you are looking for.

Stretching not applying in a WPF templated Button

I created a templated button in WPF :
<ControlTemplate TargetType="{x:Type Button}"
x:Key="BoutonGris">
<Button Foreground="White"
BorderBrush="Transparent"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<Button.Content>
<Border CornerRadius="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ContentPresenter />
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Background"
Value="#58585a" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="{DynamicResource DegradeCouleurTheme}" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Button.Content>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</ControlTemplate>
I use this button in my Window :
<Button x:Name="BtnRestoreDefault" Template="{DynamicResource BoutonGris}" Content="Rest. défaut" Height="27" Width="88" Click="Button_Click_RestoreDefault"/>
My problem is that the button don't appear to have the Height="27" and Width="88".
Here is my result in VS2012 :
The button has the good size, but the gray area don't. I have use the Stretch keywords on the Template but i don't find the mistake.
If i use Stretch for HorizontalAlignment, HorizontalContentAlignment, VerticalAlignment, and VerticalContentAlignment, the gray has the good size, but, the text content is in left/up ! I would like a center text.
Anyone have an idea please ?
Thanks a lot,
Best regards,
Nixeus
This should do the trick.
<ControlTemplate TargetType="{x:Type Button}" x:Key="BoutonGris">
<Button Foreground="White" BorderBrush="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" >
<Button.Content>
<!-- A lot of your code -->
</Button.Content>
<!-- A lot of your code -->
</Button>
</ControlTemplate>
One question, why do you have a Button in your ControlTemplate for a Button? Usually, I would expect simple controls like Border etc here, because you want to reimplement the visual appearance.
Edit
One of the ContentPresenter should be declared like this.
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
I'm not sure which one. But you can try both. ;o)

Categories