WPF Control Template Trigger Assigned to Container - c#

I've defined a control template for my top level items of a menu as follows:
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="MenuItem">
<Border x:Name="Border">
<Grid x:Name="Grid" >
<ContentPresenter
ContentSource="Header"
RecognizesAccessKey="False"
Margin="10,5,50,5"
TextBlock.FontFamily="Segoe UI"
TextBlock.FontSize="14"
TextBlock.Foreground="White"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ControlMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This is giving me the style I want, however the trigger is only triggered when I hover over the text of the menu. Ideally i want the item to become highlighted when I hover over its parent grid element. Tried changing the trigger to this
<ControlTemplate.Triggers>
<Trigger Property="Grid.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ControlMouseOver}"/>
</Trigger>
</ControlTemplate.Triggers>
but doesn't work. Any suggestions as to where I'm going wrong?

To make whole Border (or Grid) hit test visible you need to initialize Background property with some Brush. You can set it to Transparent for example
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}" TargetType="MenuItem">
<Border x:Name="Border" Background="Transparent" >
<!-- -->
</Border>
<!-- -->
</ControlTemplate>

Related

How to set a borderless button which changes its color when mouse hovering in WPF

I want to override all my button's style to a borderless grayish button which highlights when hover on.
I wrote like below:
If I remove the template section (I even have no idea of what does it do), the button will have a border even if I have set BorderThickness to 0.
But if I keep the template section, the button will not change its background color at all.
So what can I do to keep both features and why my xaml won't work?
BTW, where can I find a full list of properties/triggers that I can set for certain type of control like button?
<Style TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Background" Value="{StaticResource TitleBrush}" />
<Setter Property="Foreground" Value="{StaticResource WhiteTextBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource HoverBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Why BorderThickness value not reflected to control?
https://stackoverflow.com/a/16649319/440030
Why your xaml won't work?
Because, you set Template property of button with a simple content presenter, So Button ignore all control property and reflect your template. One way is improve your Template property with a by example label:
<ControlTemplate TargetType="{x:Type Button}">
<Label Content="{TemplateBinding Content}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black"/>
</ControlTemplate>
Try something like this it will work
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Rect" Width="100" Height="100" Fill="Aqua"/>
<Viewbox>
<ContentControl Margin="20" Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Rect" Property="Fill" Value="Orange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource buttonTemplate}">OK</Button>
</Grid>

Rounded Corner TextBox in WPF

i search the web for TextBox with rounded corners and find a xaml code like below:
<Style TargetType="{x:Type my1:CustomTextBox}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate >
<Border Background="{TemplateBinding Background}" x:Name="Bd"
BorderThickness="2" CornerRadius="5" BorderBrush="#FFF9EAB6">
***<ScrollViewer x:Name="PART_ContentHost" />***
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="#FFC7B0B0"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="#FFC7B0B0"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="False">
<Setter Property="Foreground" Value="#FFC7B0B0"/>
</Trigger>
<Trigger Property="Width" Value="Auto">
<Setter Property="MinWidth" Value="120"/>
</Trigger>
<Trigger Property="Height" Value="Auto">
<Setter Property="MinHeight" Value="27"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
i want to find out what is
<ScrollViewer x:Name="PART_ContentHost" />
in detail and why not properly work my template if delete this line from it,
please tell me completely in detail.
thanks alot.
The part named "PART_ContentHost" contains the control core, this is the textbox itself, besides the adornments. The textbox's code behind will look for it, so if you rename of delete, the control wont work.
In this case, the content is scrollable (as a textbox can scroll text horizontally and vertically).
use this part of xaml deign :
<TextBox x:Name="usernameText" Height="30" Width="300" TextWrapping="Wrap" Text="" FontSize="20" HorizontalContentAlignment="Center" LostFocus="usernameText_LostFocus">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</TextBox.Resources>
</TextBox>
If you need a simple textbox with rounded corners, you can do it like that:
<Border Padding="5" CornerRadius="5" BorderThickness="1" BorderBrush="LightGray" SnapsToDevicePixels="True" Background="White">
<TextBox Background="Transparent" BorderThickness="0">This is beautifull ;)</TextBox>
</Border>
The ScrollViewer contains the actual content of the control. Your control isn't a real textbox, but actually a border (with rounded corners) surrounding a ScrollViewer, into which you would then need to place your text. If you don't need scrolling, you can replace the ScrollViewer with a text box, i.e.:
change
<ScrollViewer x:Name="PART_ContentHost" />
to
<TextBox x:Name="PART_ContentHost" />

Turn off ListView border mouseover animations

ListView's default style animates the border colour to light blue when you mouse over the control. Is there any way of turning this off without replacing the entire control template?
I've tried
<ListView>
<ListView.Style>
<Style TargetType="ListView">
<Setter Property="BorderBrush" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
This results in a green border, which turns briefly red when you mouse over before fading to light blue. The default animations take precedence.
Am I missing something simple, or is it time for a template override?
You would have to override the ControlTemplate, as the default one uses a ListBoxChrome element which creates the effect you see. ListBoxChrome ignores the BorderBrush property when the mouse is over, as determined by it's RenderMouseOver property.
You can still use ListBoxChrome if you want, you would just have to remove the RenderMouseOver property. Assuming you are using a GridView you'd use:
xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
...
<Style x:Key="{x:Static GridView.GridViewStyleKey}"
TargetType="{x:Type ListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<theme:ListBoxChrome Name="Bd"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
RenderFocused="{TemplateBinding IsKeyboardFocusWithin}"
SnapsToDevicePixels="true">
<ScrollViewer Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}"
Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</theme:ListBoxChrome>
<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>
If you want to remove the focused look, then it probably better to just replace the ListBoxChrome with a Border element.

Transparent WPF ListBox with selectable items

Could anyone suggest how I can implement a WPF ListBox that (effectively) has a transparent/hit-test-invisible background, but whose items are still hit-test-visible?
In other words, I'd like to be able to click - through the ListBox's background - to controls underneath it, but still be able to select the ListBox's items.
I have ListBox using a custom layout panel (it's a ListBox because the items need to be selectable). However, I need this panel to be overlayed on top of other controls, allowing them to still be used normally.
I've tried various combinations of Background="Transparent" and IsHitTestVisible="False" but I suspect I might be on the wrong lines...
Hope this makes sense - I'm new to WPF so any guidance will be most appreciated! Thanks.
Try setting the background to "{x:Null} on the ListeItemContainer and the ListBox itself.
Transparent is still hit-testable, which is why you're still getting hit tests on it.
EDIT
I ran WPF Inspector on a sample and found that the ScrollViewer in the default ListBox template was causing mouse clicks to stay in the ListBox.
Here is a ListBox control template that does not include the ScrollViewer. It does allow the mouse to pass through to the TextBox that is behind the listbox, but still allows the user to select items in the listbox.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Window.Resources>
<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
<Style x:Key="ListBoxStyle1" TargetType="{x:Type ListBox}">
<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="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Width="100">
<TextBox TextWrapping="Wrap">I'm in the background. I'm in the background. I'm in the backgroun.</TextBox>
<ListBox Background="{x:Null}" Style="{StaticResource ListBoxStyle1}">
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
<ListBoxItem Margin="10" Background="#999">Hello</ListBoxItem>
</ListBox>
</Grid>
</Window>

ListBox/Rectangle Margins, Changing Look of Selected Item, Binding for Selected Item

A few questions regarding ListBox here (3 actually)
1. ListBoxItem/Rectangle Margins
From the image, I think the margins are uneven, the left seems like it have more margin. And this is when my margins is already set to
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="20" Height="20" Margin="1,2,2,2">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding}" />
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</ListBox.ItemTemplate>
2. How can I change the Selected Item Look?
I don't want that blue background, can I just have a border?
I tried the example from Change WPF DataTemplate for ListBox item if selected
with this code
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle Width="20" Height="20" Margin="1,2,3,2">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding}" />
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1">
<Rectangle Width="20" Height="20" Margin="1,2,3,2">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding}" />
</Rectangle.Fill>
</Rectangle>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
and got something like
3. Binding for Selected Item
I am trying to bind the selected color to a property of the view model. If the color in the view model does not exists in the list of colors provided, no color should be selected. Think of this as an alternative way to select color, I have selection of colors via RGB/HSB sliders. I tried
<ListBox ItemsSource="{Binding ThemeColors}" SelectedValue="{Binding Color}" SelectionChanged="ListBox_SelectionChanged" ...
then in C#
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBox)sender;
if (listBox.SelectedValue != null)
Color = (Color)listBox.SelectedValue;
}
But after that, when I try to select colors with the sliders, I get some weird jerking and sometimes the color always snap back to the color selected from the list box. But sometimes it works fine, I am quite confused.
1.ListBoxItem comes with a default Padding of "2,0,0,0", that's why the Margin seems of. This can be changed in the ItemContainerStyle of the ListBox
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0,0,0,0"/>
</Style>
</ListBox.ItemContainerStyle>
(Although I seem to get the best result with a Padding of 1,0,0,0. Can't explain that..)
2.To remove the Background and only display the Border I think you'll have to retemplate the ListBoxItem and modify the Triggers to use BorderBrush instead of Background for the Border.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="BorderBrush" TargetName="Bd" 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 Property="BorderBrush" TargetName="Bd" 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>
</ListBox.ItemContainerStyle>
For 3. I'm not sure I understand what you want to do

Categories

Resources