Rectangle IsFocused doesn't work - wpf

I have a slider and I want its thumb to change style depending on its state: mouse over or clicked.
I did try changing the thumb's style, but for no apparent reason it did nothing by the way.
So this rectangle, The IsMouseOver works just fine, but as I said, the IsFocused does nothing.
My XAML:
<Style x:Key="SliderRectStyle" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#FF5B5B5B"/>
<Setter Property="Stroke" Value="#FF5B5B5B"/>
<Setter Property="Opacity" Value="1"/>
<Setter Property="mouseHelper:MouseDownHelper.IsEnabled" Value="True"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Fill" Value="#FFF0A300"/>
<Setter Property="Stroke" Value="#FFF0A300"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="#FFD1A139"/>
<Setter Property="Stroke" Value="#FFD1A139"/>
</Trigger>
</Style.Triggers>
</Style>

You need to set the IsFocusable property of the Rectangle to true and actually focus it by calling its Focus() method to focus it:
<Rectangle x:Name="rect" Style="{StaticResource SliderRectStyle}" Width="100" Height="100" Focusable="True"
PreviewMouseLeftButtonDown="rect_PreviewMouseLeftButtonDown" />
private void rect_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
rect.Focus();
}

Related

Trigger is not working until i went to my path object

I have a style for my path object this path is surrounded by a border when I'm writing a trigger that is not working until I went on to actual path object.
Style
<Style TargetType="Path">
<Setter Property="Stroke" Value="{DynamicResource CloseButtonClr}"></Setter>
<Setter Property="Stretch" Value="Uniform"></Setter>
<Setter Property="StrokeThickness" Value="3"></Setter>
<Style.Triggers>
<Trigger Property="Border.IsMouseOver" Value="True">
<Setter Property="Stroke" Value="{DynamicResource LableClr}"/>
</Trigger>
</Style.Triggers>
</Style>
<Border Width="20" Grid.Column="2" Background="Transparent" Margin="0,0,5,0" >
<Path Data="M0,0 L1,1 M0,1 L1,0" />
</Border>
this is my code if I went on the path object then the trigger is working if went in between border and path object the trigger is not working, please help me wt I'm missing thanks
Use a DataTrigger to bind to the IsMouseOver property of the Border:
<Style TargetType="Path">
<Setter Property="Stroke" Value="{DynamicResource CloseButtonClr}"></Setter>
<Setter Property="Stretch" Value="Uniform"></Setter>
<Setter Property="StrokeThickness" Value="3"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" Value="{DynamicResource LableClr}"/>
</Trigger>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=Border}}" Value="True">
<Setter Property="Stroke" Value="{DynamicResource LableClr}"/>
</DataTrigger>
</Style.Triggers>
</Style>
A Trigger in a Path style can only bind to a property of the Path itself. The path Border.IsMouseOver will not bind to the parent Border element. It will bind to the IsMouseOver property of the Path. Both Border and Path inherit from UIElement where the property is actually defined.

ValidationTemplate not always show in TabControl

first my validation template
<ControlTemplate x:Key="ValidationTemplate" >
<Grid>
<AdornedElementPlaceholder Name="MyAdornedElement" />
<Path x:Name="path" Margin="-2,-2,0,0" Data="M 0,10 L 10,0 L 0,0 Z" Fill="{StaticResource BrushError}" StrokeThickness="2" Stroke="White"
Visibility="{Binding ElementName=MyAdornedElement,Path=AdornedElement.Visibility}"
ToolTip="{Binding ElementName=MyAdornedElement,Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
</Grid>
</ControlTemplate>
and my textbox style
<Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTemplate}"/>
<Setter Property="UndoLimit" Value="0"/>
<Style.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderThickness" Value="{StaticResource IsFocusBorderThickness}"/>
<Setter Property="BorderBrush" Value="{StaticResource IsFocusBorderBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource IsDisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding Path=(Validation.Errors).CurrentItem.ErrorContent, RelativeSource={x:Static RelativeSource.Self}}"/>
</Trigger>
</Style.Triggers>
</Style>
and now the mysterius behavior
i have a tabcontrol with 2 tabpages, each of the pages contains textboxes. if i open my view and move from first to second tabpage a back and then push the validate button - all is fine, my validation template is shown for all textboxes on both tabpages.
BUT when i just open the view and dont navigate to tabpage 2 - then push the validate button - just the textboxes on tabpage 1 have the validation template shown. even more when i hit the button again on the validation template its not show on tabpage 2.
Any hints what i'm missing?
EDIT:
if i use snoop and walk on the snoop treeview to my textbox on tabpage 2, then the validation Template Adorner is visible as far as i click on the TextBox in the Snoop Treeview...
if i add the following to my textbox style it works.
<Trigger Property="IsVisible" Value="false">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Trigger>
<Trigger Property="IsVisible" Value="true">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ValidationTemplate}"/>
</Trigger>

Change foreground color dynamically based on background color

Problem domain: In my WPF application, I change background of lot of UI controls like Button or ListItems dynamically based on data they contain. The background is changed either when the control is loaded or based on use action/data received.
Problem statement: If the background is too dark (Green/Blue) I want to set the foreground to white else black.
Constraints: I have a big application and performance is a major concern. That's why I am hesitant to use converters and am looking for some xaml/style trigger based solutions as this is just a condition based issue.
Solutions tried: To keep it simple, I am explaining what I tried for a simple wpf button:
<UserControl.Resources>
<Style x:Key="NoChromeButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{Binding Background}"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Chrome"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
Background="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Style="{StaticResource MyTextBlockStyle}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Black"/>
</Trigger>
<Trigger Property="Background" Value="White">
<Setter Property="Foreground" Value="Aqua"/>
</Trigger>
<Trigger Property="Background" Value="Transparent">
<Setter Property="Foreground" Value="BlueViolet"/>
</Trigger>
<Trigger Property="Background" Value="Green">
<Setter Property="Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="Background" Value="Yellow">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="Background" Value="Red">
<Setter Property="Foreground" Value="Yellow"/>
</Trigger>
<Trigger Property="Background" Value="Black">
<Setter Property="Foreground" Value="DarkSeaGreen"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style x:key="MyTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontStyle" Value="Italic"/>
<Style.Triggers>
<Trigger Property="Background" Value="White">
<Setter Property="Foreground" Value="Aqua"/>
</Trigger>
<Trigger Property="Background" Value="Transparent">
<Setter Property="Foreground" Value="BlueViolet"/>
</Trigger>
<Trigger Property="Background" Value="Green">
<Setter Property="Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="Background" Value="Yellow">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="Background" Value="Red">
<Setter Property="Foreground" Value="Yellow"/>
</Trigger>
<Trigger Property="Background" Value="Black">
<Setter Property="Foreground" Value="DarkSeaGreen"/>
</Trigger>
</Style>
</UserControl.Resources>
When button is created in the XAML:
<Button Content="{Binding Name}" Style="{StaticResource NoChromeButton}"/>
Also, I would like to point out a couple of things in the above style:
If I would have used ContentPresenter instead of TextBlock inside the Grid named Chrome, background property was not set on the ContentPresenter and when I snooped (http://snoopwpf.codeplex.com/) the UI, I found that the ContentPresenter has TextBlock whose Background was always set to Default and hence no styletriggers were applied to the TextBlock. Also, this TextBlock's background valuesource is Default.
On the other hand, when I use TextBlock directly inside the Grid named Chrome, I can set its background explicitly to Grid's Background which is set to Button's Background. Snooping reveals that now TextBlock's Background ValueSource is ParentTemplate.
Button picks up MyTextBlockStyle while displaying its content.
Style triggers for Button or TextBlock were never triggered unless I did mouse over the button which changes the button's background to Black and propagates this value down to TextBlock background changing the TextBlock's foreground color to DarkSeaGreen.
Also, changing the button's background in snoop utility while application is running, triggers the Style Triggers.
Questions:
Why none of the Style triggers work for Background property whereas they work for IsMouseOver property?
What I am doing wrong?
Any solution for this?
I found the solution to my problem.
TextBlock does not derive from Control. Any text shown on UI by any control internally uses TextBlock to represent the textual content. If TextBlock style is set using the following in ResourceDictionary:
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontStyle" Value="Normal" />
</Style>
Any control that represents text will have this style (since no key is assigned to this style which implies that all TextBlock will get it by default) unless the control's template override the TextBlock's default style which can be done as follows:
<Button Grid.Column="1" Style="{StaticResource NoChromeButton}">
<TextBlock Style="{x:Null}" Text="abc" FontFamily="Segoe UI Symbol"/>
</Button>
This simple setting has resolved most of the issues we have with dynamic foreground color changing.

WPF DataGrid RowStyle for selected row not changing the background and foreground color

I am using Visual Studio 2012 on windows 7. I need to know why the following style for Grid's selected row does not work for background and foreground colors but works perfectly fine for other properties like BorderBrush and BorderThickness etc? Though I can see them changing while mouse over grid rows.
<Style x:Key="gridRowStyle" TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="PeachPuff"/>
<Setter Property="Foreground" Value="BlueViolet"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="PeachPuff"/>
<Setter Property="Foreground" Value="BlueViolet"/>
<Setter Property="BorderBrush" Value="BlueViolet" />
<Setter Property="BorderThickness" Value="2" />
</Trigger>
</Style.Triggers>
</Style>
Here is how I am using on grid.
<DataGrid RowStyle="{StaticResource gridRowStyle}">
I am stressing on to know "why" rather than solution to the problem as I already have solution to problem if I use grid cell style instead of rowstyle like following:
<Style x:Key="gridCellStyle" TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="PeachPuff"/>
<Setter Property="Foreground" Value="BlueViolet"/>
</Trigger>
</Style.Triggers>
</Style>
In the Default style of the DataGridCell having the following default style trigger.
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
So if you written trigger for DataGridRow, then it will only apply to the element that was placed before the DataGridCell in visual tree.
So to change the Background & Foreground while selection, you must write the trigger in DataGridCell style or remove the default trigger from the style.
Simply remove this attributs at row level in the datagrid, they have priority over the trigged properties.
nezac

Trigger doesn't work

I have an user control, It is editable text block. The content of the control is:
<DataTemplate x:Key="DisplayModeTemplate">
<TextBlock
Text="{Binding ElementName=mainControl, Path=FormattedText}"
Margin="5,3,5,3" />
</DataTemplate>
<Style TargetType="{x:Type Controls:EditableTextBlock}">
<Setter Property="ContentTemplate" Value="{StaticResource EditModeTemplate}"/>
<Style.Triggers>
<Trigger Property="IsInEditMode" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource EditModeTemplate}" />
</Trigger>
<Trigger Property="IsInEditMode" Value="False">
<Setter Property="ContentTemplate" Value="{StaticResource DisplayModeTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
Also i have another window with tree view:
When treeView1_KeyDown fires I set IsInEditMode to true, but it seems that trigger doesn't work, because content template don't change. Anyone, please explain me why?
Have you tried removing the default setter?
i.e. change your style code to:
<Style TargetType="{x:Type Controls:EditableTextBlock}">
<Style.Triggers>
<Trigger Property="IsInEditMode" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource EditModeTemplate}" />
</Trigger>
<Trigger Property="IsInEditMode" Value="False">
<Setter Property="ContentTemplate" Value="{StaticResource DisplayModeTemplate}" />
</Trigger>
</Style.Triggers>
</Style>

Resources