WPF DockPanel IsMouseOver only triggered when child controls are moused over - wpf

I have a sort of tile system for my application. See the below code:
<WrapPanel Grid.Column="0" Grid.Row="1">
<DockPanel Style="{StaticResource Panel}">
<Label Content="Upload"/>
<Image Width="40">
<Image.Source>
<BitmapImage DecodePixelWidth="40" UriSource="images/download.png" />
</Image.Source>
</Image>
</DockPanel>
</WrapPanel>
As you can see, I have got the main container ([icode]WrapPanel[/icode]), and then I have got multiple [icode]DockPanel[/icode]'s which makeup the tile itself.
For some reason when I mouseover the DockPanel, the IsMouseOver trigger doesn't trigger, but it does when I mouse over any of it's children. Once triggered it remains triggered until my mouse leaves the DockPanel.
Here is the style:
<Style x:Key="Panel" TargetType="DockPanel">
<Setter Property="Margin" Value="4" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Height" Value="118" />
<Setter Property="Width" Value="118" />
<Setter Property="LastChildFill" Value="True" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF212121" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Label">
<Setter Property="Foreground" Value="White" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Margin" Value="3" />
<Setter Property="DockPanel.Dock" Value="Bottom" />
</Style>
</Style.Resources>
</Style>
Any ideas?

Try to set DockPanel's background to Transparent.
When background is null, WPF will not include it in hit test.

Related

Change Viewbox Path Data based on DataTrigger value

I have the following XAML where I declare a Button containing a Viewbox that displays Geometry data. After MANY attempts and reviewing SO questions, I still cannot get the Geometry data to appear inside the button.
<Button
x:Name="ChangeViewButton"
Style="{DynamicResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}">
<Viewbox Margin="-10">
<Viewbox.Style>
<Style TargetType="Viewbox">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Path.Stretch" Value="Uniform" />
<Setter Property="Path.StrokeThickness" Value="2" />
<Setter Property="Path.Stroke" Value="{Binding ElementName=ChangeViewButton, Path=Foreground}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="DataGridView">
<Setter Property="Path.Data" Value="{StaticResource GridGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Grid View"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="TileView">
<Setter Property="Path.Data" Value="{StaticResource TileGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Tile View"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>
</Button>
The DataTriggers are bound to an enum value in the ViewModel that is defined as follows:
public enum CylinderManagementViewTypes
{
DataGridView,
TileView
}
private CylinderManagementViewTypes _cylinderManagementViewType;
public CylinderManagementViewTypes CylinderManagementViewType
{
get { return _cylinderManagementViewType; }
set { SetProperty(ref _cylinderManagementViewType, value); }
}
The Geometry data is defined in a Resource Dictionary as:
<Geometry x:Key="TileGlyph">
M5.9,6 18.9,6 18.9,19 5.9,19zM31.1,6 44.1,6 44.1,19 31.1,19zM5.9,30.9 18.9,30.9 18.9,43.9 5.9,43.9zM31.1,30.9 44.1,30.9 44.1,43.9 31.1,43.9z
</Geometry>
<Geometry x:Key="GridGlyph">
M19.1,6.1 19.1,25 19.1,43.9M31.2,6.1 31.2,25.2 31.2,43.9M44.2,19.1 25.1,19.1 6.1,19.1M44.2,30.9 25.1,30.9 6.1,30.9M44,43.9 6,43.9 6,5.9 44,5.9z
</Geometry>
If I just declare the Button as follows, the Geometry data is displayed in the button:
<Button
x:Name="ChangeViewButton"
Style="{DynamicResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}"
ToolTip="Change to Grid View">
<Viewbox Margin="-10">
<Path
Data="{StaticResource GridGlyph}"
Stroke="{Binding ElementName=ChangeViewButton, Path=Foreground}"
Style="{StaticResource IconPath}" />
</Viewbox>
</Button>
where IconPath is defined as:
<Style x:Key="IconPath" TargetType="Path">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="StrokeThickness" Value="2" />
</Style>
Any help solving this is greatly appreciated!
Well after doing even more investigation, and taking a hint from this SO post answer, I discovered that I needed to set the Style on the Path rather than the Viewbox. The Button declaration works and now appears as:
<Button
x:Name="ChangeViewButton"
Style="{StaticResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}">
<Viewbox Margin="-10">
<Path>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Data" Value="{StaticResource GridGlyph}"/>
<Setter Property="ToolTip" Value="Change to Grid View"/>
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="Stroke" Value="{Binding ElementName=ChangeViewButton, Path=Foreground}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="TileView">
<Setter Property="Path.Data" Value="{StaticResource TileGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Tile View"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Viewbox>
</Button>

Binding TexBox Name to TextBlock Name, Placeholder

Short background on the problem: I am trying to make a readable, xaml only TextBox Placeholder, which is packed to a ResourceDictionary.
At this point - I have made a well working prototype, which looks and used on the page like this:
<Grid>
<TextBox Style="{StaticResource SearchBox}"
Width="325"
x:Name="UsarioDisponiblesSearch"/>
<TextBlock IsHitTestVisible="False"
Text="Search..."
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"
Foreground="{StaticResource WhiteFadedBrush}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=UsarioDisponiblesSearch}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Image Source="/img/search.png" Height="15" HorizontalAlignment="Right" Margin="0,0,5,0" />
</Grid>
Grid, that holds the SearchBox consist of 3 elements:
TextBox - which will receive search string;
TextBlock - which actually holds the PlaceHolder. It disapears, as soon as ElementName of TextBox is not an empty string;
Image - custom icon on the right from the SearchBox.
What I want to achieve is a look like this on the page:
<Grid>
<TextBox Style="{StaticResource SearchBox}"
Width="325"
x:Name="UarioDisponiblesSearch"/>
<TextBlock Style="{StaticResource PlaceHolder}"
x:Name="{Binding Text, ElementName=UarioDisponiblesSearch}" />
</Grid>
And like around this styles, described in the ResourceDictionary:
<Style x:Key="SearchBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="5,0,0,0" />
<Setter Property="Foreground" Value="{StaticResource WhiteBrush}" />
</Style>
<Style x:Key="Placeholder" TargetType="{x:Type TextBlock}">
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Text" Value="Search..." />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5,0,0,0" />
<Setter Property="Foreground" Value="{StaticResource WhiteFadedBrush}" />
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
The main obstacle on my way there is the Binding, because I am not really good still in understanding how does it work, and the fact, that at this point three elements will have to share the same Name property (Which I suppose is a pretty huge obstacle as well).
I am not sticking to exactly this construction but I want it to be reusable, useful for the community and neat looking.
This XAML will give a templated TextBox that will display a given message if the Text is empty on the TextBox and it does not have focus. So when you click it the message disappears, and if you enter text (or have bound text) the message will also disappear.
You can do any further fancy bindings and such if you want to make it more re-usable. I.E. you could templatebind the DisplayText.Text to something to allow for dynamic messages.
When I was doing a quick search as I was styling, I stumbled on This, which is almost the same thing. So it would be worth giving fair reference. I prefer to use keys and compartmentalize my templates and styles. In the event I want a slightly different style elsewhere, then i can just do a BasedOn Style (which i do often). It is really 6 of one and half a dozen of another (although I didn't test the linked code).
<ControlTemplate x:Key="SearchMessageTextBoxControlTemplate" TargetType="{x:Type TextBox}">
<Grid>
<Grid x:Name="SearchTextGrid">
<ScrollViewer x:Name="PART_ContentHost" Background="{TemplateBinding Background}" />
<TextBlock x:Name="DisplayText" Text="Type Your Search..."
HorizontalAlignment="Center"
VerticalAlignment="Center"
Opacity="0.5"
Visibility="Hidden"
FontSize="{TemplateBinding FontSize}"/>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="DisplayText" Property="Visibility" Value="Hidden"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="False"/>
<Condition Property="Text" Value=""/>
</MultiTrigger.Conditions>
<Setter TargetName="DisplayText" Property="Visibility" Value="Visible"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="WaterMarkMessageTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="20"/>
<Setter Property="Background" Value="DarkSlateGray"/>
<Setter Property="CaretBrush" Value="White"/>
<Setter Property="Foreground" Value="#F2FFE5"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Template" Value="{StaticResource SearchMessageTextBoxControlTemplate}"/>
</Style>
You would use it as follows:
<TextBox Style="{StaticResource WaterMarkMessageTextBoxStyle}"/>

XAML/WPF focus textblock

Are textblocks focusable in WPF? I want to change the background color of the textblock if it is currently the one focused, but I want to do it in XAML.
This is what I have now. It is a bunch of textboxes in a Stackpanel. I can get the XAML to target the non focus or base state, but when I try to add a trigger, the background does not change on focus. Code is below:
<Style x:Key="QueueListTextBlocks" TargetType="TextBlock">
<Setter Property="Background" Value="#027802"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Padding" Value="10,5"></Setter>
<Setter Property="Margin" Value="5,2,5,0"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Focusable" Value="true"/>
<Setter Property="Cursor" Value="Hand"></Setter>
<!-- Trigger-->
<Style.Triggers>
<!--Does not pick up a IsFucused State--Alternative?-->
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Blue"></Setter>
<Setter Property="FontSize" Value="18"></Setter>
<Setter Property="Foreground" Value="Orange"></Setter>
</Trigger>
</Style.Triggers>
<!--<Setter Property="Background" Value="White" />-->
</Style>
I tried your style and it works perfectly.
TextBlocks in my window change their look just pressing the TAB key.
I'm using .NET 4.0 framework.
This is the XAML of my window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="TextBlock" x:Key="TextBlockStyle">
<Setter Property="Background" Value="#027802"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
<Setter Property="Padding" Value="10,5"></Setter>
<Setter Property="Margin" Value="5,2,5,0"></Setter>
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Focusable" Value="true"/>
<Setter Property="Cursor" Value="Hand"></Setter>
<!-- Trigger-->
<Style.Triggers>
<!--Does not pick up a IsFucused State-Alternative?-->
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Blue"></Setter>
<Setter Property="FontSize" Value="18"></Setter>
<Setter Property="Foreground" Value="Orange"></Setter>
</Trigger>
</Style.Triggers>
<!--<Setter Property="Background" Value="White" />-->
</Style>
</Window.Resources>
<StackPanel Orientation="Vertical">
<TextBlock Text="One" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text="Two" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text="Three" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text="Four" Style="{StaticResource TextBlockStyle}" />
<TextBlock Text="Five" Style="{StaticResource TextBlockStyle}" />
</StackPanel>
</Window>
I hope it helps

WPF buttons (image & label) shadowing

I want to create buttons which have a image and a text included and get a nice shadowing. Particularly, I want the image and label have a light grey shadowing, but when moving the mouse over the button I'd like a kind of blue shadowing. Moving away sets it back to light grey. I would need some help as I just can't figure out how to achive it (I'm new to WPF).
The Buttons looks like ...
<Button>
<Button.Content>
<StackPanel Orientation="Vertical">
<Image Source="Images/preferences-system.png" />
<Label HorizontalAlignment="Center">Settings</Label>
</StackPanel>
</Button.Content>
</Button>
The Canvas goes ...
<Canvas DockPanel.Dock="Left" Background="#FF349EBC">
<Canvas.Resources>
<DropShadowEffect x:Key="dropMouseOverShadow" Color="#FFD9EDF3" Opacity="80" Direction="270" />
<DropShadowEffect x:Key="dropLightShadow" Color="LightGrey" Opacity="10" Direction="270" BlurRadius="20" />
<Style TargetType="{x:Type Button}">
<Style.Setters>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" CornerRadius="2">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{StaticResource dropMouseOverShadow}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style TargetType="{x:Type Image}">
<Style.Setters>
<Setter Property="Effect" Value="{StaticResource dropLightShadow}" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Label}">
<Style.Setters>
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Gill Sans MT" />
<Setter Property="Effect" Value="{StaticResource dropLightShadow}" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
What I get is a light grey shadowing on image and labels on begin. Moving the mouse over the button the grey and light blue get mixed. When moving further on the image it gets the light blue only. The same goes for the label.
How can I achive switching the shadowning to light blue when I mouse over the button and not the image and label itself? Anyone an idea or an completly other approach?
Apply the LightGray Effect to the ContentPresenter. Then on the IsMouseOver Trigger, set the Effect property of the ContentPresenter to the blue Effect.
NOTE: Accomplish this by setting the x:Name attribute of the ContentPresenter, then accessing the ContentPresenter by name via the Setter using TargetName.
NOTE: Remove the various other Effect settings in the styles of the child elements. Applying the Effect to the ContentPresenter causes the child elements to inherit the Effect.
<Canvas DockPanel.Dock="Left" Background="#FF349EBC">
<Canvas.Resources>
<DropShadowEffect x:Key="dropMouseOverShadow" Color="#FFD9EDF3" Opacity="80" Direction="270" />
<DropShadowEffect x:Key="dropLightShadow" Color="LightGrey" Opacity="10" Direction="270" BlurRadius="20" />
<Style TargetType="{x:Type Button}">
<Style.Setters>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" CornerRadius="2">
<ContentPresenter x:Name="cp" Effect="{StaticResource dropLightShadow}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="cp" Property="Effect" Value="{StaticResource dropMouseOverShadow}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style TargetType="{x:Type Label}">
<Style.Setters>
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Gill Sans MT" />
</Style.Setters>
</Style>

WPF Mouseover Trigger Effect for Child Controls

Lets say I have this bit of code:
<Window>
<Window.Resources>
<Color x:Key="MyColor"
A="255"
R="152"
G="152"
B="152" />
<DropShadowEffect x:Key="MyEffect"
ShadowDepth="0"
Color="{StaticResource MyColor}"
BlurRadius="10" />
<Style x:Key="MyGridStyle"
TargetType="{x:Type Grid}">
<Setter Property="Height"
Value="200" />
<Setter Property="Width"
Value="200" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Width"
Value="100" />
</Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Height"
Value="100" />
<Setter Property="Width"
Value="100" />
</Style>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<!-- How do I apply my effect when this grid is hovered over to Image and TextBox, but not the grid itself? -->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Style="{StaticResource MyGridStyle}">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Row="0"
Grid.Column="0"
Source="image.png" />
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="Hover Over Me" />
</Grid>
</Window>
Basically I have a Style applied to the Grid that says any TextBlock or Image within it should be styles to a certain size.
I want to create a Trigger on the Grid that causes an effect to be applied to all TextBlocks and Images within the Grid, but not to the Grid itself.
I can apply the Trigger directly to TextBlock and/or Image, but then the effect only occurs on each element separately. I need to have the effect occur to any TextBlock and/or Image within the Grid despite which inner child element I am hovered over.
Can anyone help me with this?
You can do it the other way around. That is, add DataTriggers to Image and TextBlock and make them trigger on IsMouseOver for the ancestor Grid.
Note: If you want this effect to trigger as soon as the mouse is over the Grid you will need to set Background to a value, like Transparent. By default, the Background is null and this value isn't used in hit testing.
<Style x:Key="MyGridStyle" TargetType="{x:Type Grid}">
<!--<Setter Property="Background" Value="Transparent"/>-->
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="200" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Width" Value="200" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Effect" Value="{StaticResource MyEffect}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Height" Value="200" />
<Setter Property="Width" Value="200" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Grid},
Path=IsMouseOver}" Value="True">
<Setter Property="Effect" Value="{StaticResource MyEffect}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
We once had a similar requirement of outer glowing ONLY the content of a row of a list box, not the row overall. We took help of this article... http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container.

Resources