How to make WPF text on Aero glass background readable? - wpf

I have a WPF app that draws text on an Aero glass background. The problem is that based on what is displayed behind my application, the text drawn on the glass background can become hard-to-read to downright-impossible-to-read.
As you can see in the following screenshot, the Save, Undo and Redo text blocks become hard to read if the window behind my application is dark.
Now, Microsoft applications, such as Word, solve this with a kind of blur behind text, as you can see in the next screenshot:
I've heard there is some kind of Win32 API call I can make to get this to work. However, that is just hearsay to me at this point, I have no facts to back that up.
I've tried a few different WPF-specific things to approximate what Word does:
Drop shadows on text
Transparent images of text with a blur baked in (instead of a TextBlock)
None of those give me usable results, they all look pretty crummy. Does anyone know of any method, WPF or Win32, that I could use to draw text the way Microsoft does on glass (i.e., readable)?

I was able to solve this without Win32 (requires .NET 3.5).
<Grid>
<TextBlock Foreground="Black" HorizontalAlignment="Center" Margin="0,10,30,0" Text="Text that should be visible on Aero Glass">
<TextBlock.Effect>
<BlurEffect Radius="15" KernelType="Gaussian">
</BlurEffect>
</TextBlock.Effect>
</TextBlock>
<TextBlock HorizontalAlignment="Center" Foreground="White" Margin="0,10,30,0" Text="Text that should be visible on Aero Glass">
</TextBlock>
</Grid>
This code has the effect of doubling up text and blurring the version of the text that is farther behind, Z-index wise. Works like a charm for me.
One thing to note:
This seems to work best if the text color is white and the blur color is black. It doesn't look so good the other way around. The good news is it looks good regardless of what is behind your Aero Glass window.

The Win32 function you are searching for is DrawThemeTextEx. It has a flag that allows you to draw text with a white glow/blur in the background.
You can find an example here: C# Transparent GUI

In case anyone looking for another example, try this it includes backward support for non glass:
Usage:
Style="{StaticResource glassText}"
Goes in a resource dictionary:
<Style TargetType="TextBlock" x:Key="glassText">
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="Foreground" Value="Black">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="White" BlurRadius="10" RenderingBias="Performance" ShadowDepth="0" Direction="0" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBlock" x:Key="glassLink" BasedOn="{StaticResource glassText}">
<Setter Property="Foreground" Value="#FF0066CC" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="TextDecorations" Value="Underline" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{x:Static SystemColors.GrayTextBrush}" />
</Trigger>
</Style.Triggers>
</Style>

Related

WPF Control Focus with Touch Screen Monitor and Windows 10

I am developing an application using WPF and VB.net in Visual Studio 2013. This application is to run on a computer with a touch screen monitor.
My development PC is running windows 7, but the computer that will be running this application is using Windows 10. I don't know if this is a specific issue to Windows 10 or a touch interface.
The issue I am having is when using the touch screen monitor, a control is highlighted after you touch the control. I cannot figure out how to automatically remove this highlight. I have tried to change focus and/or set focusable property to false. The only way to stop the control from being highlighted is to touch somewhere else on the screen.
But in Windows 7 using a mouse, I can change focus and with the focusable property set to false; the control does not receive focus at all.
This program is being used without a keyboard(physical or virtual) or mouse. Having a control highlighted is undesirable, in my opinion.
Any advice on how to remove the highlight or prevent it altogether would be greatly appreciated.
All the buttons are highlitghed while the cursor is on them, if you want you can disable the hightlight but it will be disable always. To do so create a custom style and give it to your button, i give you an example:
<Window.Resources>
<Style x:Key="CloseButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="1"
Padding="4,2"
BorderBrush="Transparent"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="Red" />
<Setter TargetName="border" Property="BorderBrush" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
this piece of code remove the highlight of your button and change is background to red when you enter it with your cursor. To add it to your button do like this:
<Button x:Name="CloseButton" Style="{StaticResource CloseButtonStyle}" />
Hope it helps :)

In code-behind how can I override tabitem colors set by an application-wide theme?

I change the background color of my TabItem conditionally in code behind. This works fine as long as no theme is set in the App.xaml. How can I change colors of a TabItem (in code) while keeping an application-wide theme?
Background:
I'm using a free WPF theme from Nukeation Reuxables. The theme is set in the Application.Resources section of my App.xaml:
<ResourceDictionary Source="/ReuxablesLegacy;component/Edge.xaml" />.
I'm trying to conditionally set the background color of a TabItem in code behind:
MyTabItem.Background = new SolidColorBrush(Colors.Gray);
The background color changes if I remove or comment out the App.xaml line that sets the theme. Why does the theme break my code? I'm changing the tab color (as data is loaded) to show which tabs contain data.
I'm aware that XAML and binding are typically used to change colors, but the solutions I've attempted seem overly complex. Here is my related StackOverflow question seeking an all XAML and binding solution. The answers given just raised more questions which I haven't found answers to.
Thanks in advance.
Edit:
The problem does not happen when changing the background of a button:
button1.Background = new SolidColorBrush(Colors.Red);
The button changes color as expected (while using an application-wide theme).
It REALLY depends on how the theme itself is implemented. If the theme was using TemplateBinding to bind to the background color of the tab to the theme's controls, then your code behind solution would work. That is probably why your button properly changes background colors in your example.
You'll probably have to dig deep into the tab's style xaml, and modify it there first for the codebehind solution to work.
If you look at the ControlTemplate of TabItem its Background property is bound to a internal resource it doesn't do TemplateBinding, I presume the theme has just given colors to it. For your code to work you have to restyle it.
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Margin="0,0,-4,0"
Background="{TemplateBinding Background}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have made two changes to the normal ControlTemplate, you can do the same to your theme.xaml.
Changed Background="{StaticResource LightBrush}" to Background="{TemplateBinding Background}"
Removed Background setter in IsSelected = True trigger.
Unfortunately, this is a simple problem with no simple answer (that I have found so far). Taking a different path to satisfy users was my final solution.
Instead of attempting to change the TabItem Background color I simply change the TabItem Foreground color to Gray if NO data exists. I also add the word "Blank" like this: "Tab 1 Blank", "Tab 2 Blank", etc. This an effective solution to the original problem. I describe it in detail here.

How to you transform these image togglebuttons into vector togglebuttons?

I have just implemented these ToggleButtons using ControlTemplates that set the Image content according to IsChecked stated. The images are made in Photoshop, but I want them as WPF vectors.
The buttons look like these when IsChecked=False:
And when IsChecked=True I just replace the Image with another PNG:
I've designed the button images in photoshop. They have the following image layers:
Translucent shape (a square with two round corners for the edge buttons)
Translucent lines for division lines
Icon
Text
Translucent gradient for the glass reflex effect
I recognize that this is not the most flexible design and I'd rather have the same buttons in a vector form, but I have no idea on how to do it.
Here's the xaml from one of the buttons (feel free to suggest other alternatives on how to implement the buttons as well):
<ControlTemplate x:Key="ResetButtonTemplate" TargetType="{x:Type ToggleButton}">
<Image x:Name="ImageReset" Source="images\button_reset_gray.png"/>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Cursor" Value="Hand" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ImageReset" Property="Source" Value="images\button_reset_red.png"/>
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Cursor" Value="Arrow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<StackPanel Orientation="Horizontal" Margin="20">
<ToggleButton Name="buttonRun" Width="102" Height="102" Template="{StaticResource RunButtonTemplate}" Checked="buttonRun_Checked" />
<ToggleButton Name="buttonPause" Width="102" Height="102" Template="{StaticResource PauseButtonTemplate}" Checked="buttonPause_Checked" />
<ToggleButton Name="buttonReset" Width="102" Height="102" Template="{StaticResource ResetButtonTemplate}" Checked="buttonReset_Checked" />
</StackPanel>
Try to look at Expression Studio. Some of the apps in the suite have ability to import photoshop formats.
Although, in the worst case, manually creating such images in Blend is not a big deal.

Changing Hyperlink foreground without losing hover color

I'm writing a WPF app, and I want some of my hyperlinks to be the default blue, and others to be green. No problem -- I can just set Foreground:
<TextBlock><Hyperlink Foreground="#0C0">Mark as done</Hyperlink></TextBlock>
The trouble is, when I do this, the hover effect goes away. In a normal Hyperlink, when I move the mouse over the link, it turns red, and when I move the mouse away, it goes back to blue. But in a Hyperlink with the Foreground property assigned, it's always that color -- the red-on-hover is totally suppressed.
How can I change a Hyperlink's color, without losing the default hover behavior and color?
Setting the Foreground directly (as you've done) doesn't work, and setting it in a Style doesn't work either, unless you "derive" that style from the default Hyperlink style (which must include the OnMouseOver trigger). So this works:
<TextBlock>
<Hyperlink>
<Hyperlink.Style>
<Style TargetType="Hyperlink"
BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="#0C0"/>
</Style>
</Hyperlink.Style>
Mark as done
</Hyperlink>
</TextBlock>
Extracting that style back into the Window resources and referencing it with a key would probably make for more-readable XAML, but the above code does the job.
You should build your Hyperlink like this
<TextBlock Width="Auto" HorizontalAlignment="Center">
<Hyperlink Click="ForgotPassword_Clicked">
<TextBlock Text="Forgot Password?"/>
</Hyperlink>
</TextBlock>
And then this style should work for you
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="TextBlock.TextDecorations" Value="{x:Null}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="TextBlock.TextDecorations" Value="Underline" />
</Trigger>
</Style.Triggers>
</Style>

WPF LinkLabel implementation strategy

I am attempting to create a LinkLabel control for WPF. Essentially, I'm going to create the LinkLabel from a TextBlock and handle MouseEnter, MouseLeave, and MouseLeftButtonUp events. In the back end I have a base class that has properties that you would expect to see with a LinkLabel. With most other clickable controls in WPF, there is a default MouseEnter animation where the control becomes Ice Blue. I would like to duplicate this behavior when the mouse cursor enters over the TextBlock. I'm not sure if I'm needing to derive from ButtonBase or something along those lines. I have a I am able to change the cursor to a hand, and handle the event for when the "LinkLabel" is clicked. If accessing this seemingly default color changing animations, then I just may have to resort to a simple foreground color swap without the smooth transition. If anyone has created a custom WPF LinkLabel before or has any advice into the matter your input would be much appreciated.
You can create the equivalent of WinForms' LinkLabel right now using a combination of TextBlock and HyperLink:
<TextBlock>Here is a <Hyperlink NavigateUri="http://example.com">link</Hyperlink></TextBlock>
You won't get the "ice blue" mouse-over effect, but you will get the hand cursor. I'm sure you can introduce your mouse-over effects using a simple style trigger.
The "NavigateUri" property works in navigation-style applications where the hyperlink is inside a Frame control. In a standard WPF application you'll want to handle the Hyperlink's Click event instead and use Process.Start to kick off a web browser with the correct URL.
I just created a style for a button and apply a style to a button whenever you want LinkLabel look. Click event of button is used to perform a function when the text is clicked.
<Style x:Key="LinkLabelButtonStyle" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="CornflowerBlue"></Setter>
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="Transparent">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextDecorations="Underline" Text="{TemplateBinding Content}"></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="DarkBlue"></Setter>
<Setter Property="MinWidth" Value="90"></Setter>
<Setter Property="HorizontalAlignment" Value="Left"></Setter>
<Setter Property="Padding" Value="5"></Setter>
<Setter Property="Margin" Value="5"></Setter>
<Setter Property="Cursor" Value="Hand"></Setter>
</Style>
You can place above style in the Window.Resources so you can use it in entire window.
Then apply the style to a button whenever you want LinkLabel look.
<Button Name="LinkLabelLookALikeButton" Content="Text goes here" Style="{StaticResource LinkLabelButtonStyle}" Click="Event_Goes_Here">
</Button>
Hope this helps!

Resources