WPF button focus style being overriden when placed in content presenter - wpf

The Setup
I have the following style that I apply to most of the windows in my application:
<ResourceDictionary x:Class="MyNamespace.ChromeWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="CustomChromeTest" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid x:Name="GridMain" Background="{StaticResource MainFormColor}">
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I use it to customize the window chrome around my window (I have removed that part) so all the actual contents of the window go inside the content presenter. I use this style like so:
<Window x:Class="MyNamespace.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300"
Style="{DynamicResource CustomChromeTest}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WPFControlLibrary;component/Resources/ChromeWindow.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
</StackPanel>
This XAML above produces a window that looks like this:
The Problem
In a normal window, when the user is tabbing through the controls, the current button is highlighted to show the user the current button. Note the border around the 3rd button below.
For some reason, the moment I use my style, this feature disappears and there is no indication of which button has focus, even though the user can tab like normal. Why is this and how can I restore the built-in functionality.
Please Note
I use this style with dozens of windows and hundreds of controls. I do not want to use a style on every control with a trigger that displays a border when the control has focus. I want to restore the default functionality that was being used before I applied my custom window style.

You'll just need to define the ContentPresenter as AdornerDecorator for Window and it will work as intended. Which I didn't figure out at first either apparently :)
Style;
<Style x:Key="CustomChromeTest" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid x:Name="GridMain" Background="Yellow">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and your window...
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2" x:Name="Testeroo"
x:Class="WpfApplication1.MainWindow"
mc:Ignorable="d" Style="{StaticResource CustomChromeTest}"
Title="MainWindow" Height="550" Width="750">
<StackPanel>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
<Button Margin="5" Content="Button" Width="75"/>
</StackPanel>
</Window>
Hope this helps, cheers.

Related

Control Template not recognized in XAML using VS

I'm new to VS and XAML and I was following a tutorial on using control templates to
customize buttons.
<Window x:Class="Kromelodeon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Kromelodeon"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="399,70,0,0" VerticalAlignment="Top" Width="75"/>
<Button.Template>
<ControlTemplate TargetType="Button">
<Ellipse Fill="Orange"></Ellipse>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"></ContentPresenter>
</ControlTemplate>
</Button.Template>
</Grid>
For some reason, I'm getting an error that "Template" is not recognizable
or accessible on line 10
Can anyone point out why? I was originally trying to make four-sided diamond-shaped buttons using the
Path controls ie M 0,0 100,100 etc but got so many error codes I decided to start over with something simpler. This is a WPF desktop app.
Please help.
Your ControlTemplate needs to be inside the begin and end tags of the button like below.
Also, your ControlTemplate needs to have a root element. In this case I used a Grid which is very common.
Elements that sit on a line by themselves and have no children (nested elements) can be closed off with />
<Button Content="Button"
HorizontalAlignment="Left"
Margin="399,70,0,0"
VerticalAlignment="Top"
Width="75">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="Orange" />
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>

Set margin for all controls and textblocks using WPF style

I would like to set the margin for all controls and TextBlocks using style. Here is my window XAML without using styles:
<Window x:Class="Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window2" Height="150" Width="300">
<StackPanel>
<TextBlock Margin="5" Text="Test" Foreground="White"/>
<TextBox Margin="5">Test</TextBox>
<Button Margin="5">Test</Button>
</StackPanel>
</Window>
and this is the expected result:
I do understand that TextBlock is FrameWorkElement and TextBox & Button is a Control (which is a FrameWorkElement). Margin property is introduced on the FrameWorkElement so I have tried setting Margin on the FrameWorkElement without success:
<Window x:Class="Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window2" Height="150" Width="300">
<StackPanel>
<StackPanel.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="5"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="Test" Foreground="White"/>
<TextBox>Test</TextBox>
<Button>Test</Button>
</StackPanel>
</Window>
How can I set the margin for all framework element using style?
TargetType must match the exact type of the FrameWorkElement. Defining a style for FrameWorkElement does not apply the style to child classes (e.g. the TextBlock).
So it is not possible to to set the margin this way. It is possible to set the margin by adding a Key to the style and selecting this style for each element one by one
<Window x:Class="Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window2" Height="150" Width="300">
<StackPanel>
<StackPanel.Resources>
<Style x:Key="MX">
<Setter Property="FrameworkElement.Margin" Value="5"/>
</Style>
</StackPanel.Resources>
<TextBlock Style="{StaticResource MX}" Text="Test"/>
<TextBox Style="{StaticResource MX}">Test</TextBox>
<Button Style="{StaticResource MX}">Test</Button>
</StackPanel>
<Window.Resources>
<!-- One style for each *type* of control on the window -->
<Style TargetType="TextBox">
<Setter Property="Margin" Value="10"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="10"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="TextBox"/>
<TextBlock Text="TextBlock"/>
</StackPanel>

To change window properties by event handler

I need to change properties (ex background color) of Window based on Event handler.
we can easily do this to any controls inside window by writing it in windows.Resources as shown below.
<Window x:Class="WpfApplication8.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication8"
mc:Ignorable="d"
>
<Window.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type Button}" >
<EventSetter Event="SizeChanged" Handler="OnbuttonLoaded"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Button x:Name="Button1" Width="100" Height="20"/>
<Button Width="100" Height="20"/>
<Button Width="100" Height="20"/>
<Button Width="100" Height="20"/>
<Button Width="100" Height="20"/>
</StackPanel>
</window>
xaml.cs is as follows
private void OnbuttonLoaded(object sender, RoutedEventArgs e)
{
Button1.Background = Brushes.Red;
}
But when I have to change background color of window itself when it's SizeChanged. what can i do???
Please do help.... Thank you
And why not to use Window Style property?
<Window.Style>
<Style TargetType="{x:Type Window}">
<EventSetter Event="SizeChanged" Handler="EventSetter_OnHandler"/>
</Style>
</Window.Style>
If you need some global solution, put it in App Resources.

I want to put a close button in app.xaml window content template in wpf

I have created custom template of target type window now i want that whenever i declare the template the button automatically arrives as a close button on top right corner to close the window but in code of app.xaml i am not getting any idea to perform form closing handler on button click.
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="MyWindowStyle" TargetType="Window">
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="Background" Value="#FFCDFF"></Setter>
<Setter Property="WindowState" Value="Maximized"></Setter>
</Style>
<ControlTemplate TargetType="Window" x:Key="WindowTemplate">
<AdornerDecorator>
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Control x:Name="FocusCatcher"></Control>
<TextBlock Text="Menu Section" HorizontalAlignment="Center"/>
<Button Content="X" FontFamily="Tahoma" Width="25" HorizontalAlignment="Right"></Button>
<ContentPresenter Grid.Row="1" />
<StatusBar Height="23" VerticalAlignment="Bottom" Grid.Row="2">
<TextBlock Text="Current Editing Mode" />
</StatusBar>
</Grid>
</AdornerDecorator>
</ControlTemplate>
</Application.Resources>
And In Mainwindow.xaml
<Window x:Class="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" Style="{StaticResource MyWindowStyle}" Template="{StaticResource WindowTemplate}">
<Grid>
</Grid>
The Form Looks Somehow like this :
if I get you right you want on button click window to close?
then add some extra to your button xaml:
<Button x:Name="someName" Content="X" FontFamily="Tahoma" Width="25" HorizontalAlignment="Right" Click="someName_Click"></Button>
and implement in the code
Private Sub someName_Click(sender As Object, e As EventArgs) Handles someName.Click End Sub
to close it.

WPF - Binding IsMouseOver to Visibility

I have a window which overrides a RadioButton's ControlTemplate to show a custom control inside of it. Inside the custom control, I have a button's visibility tied to IsMouseOver, which works correctly in showing the button only when the mouse is hovering over the control. However, when I click on the RadioButton, the Button disappears. After some debugging and reading, it seems that the RadioButton is capturing the mouse on click, and this makes IsMouseOver for the UserControl false.
I tried binding the Button's visibility to FindAncestor {x:Type RadioButton} and it works, but it seems a bit fragile to me to have the UserControl depend on who is containing it. The code for the window and the user control is below. Any suggestions?
<Window x:Name="window" x:Class="WPFTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WPFTest="clr-namespace:WPFTest"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<WPFTest:TestUC />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Border BorderBrush="Black" BorderThickness="2">
<StackPanel>
<RadioButton x:Name="OptionButton" Height="100" />
<TextBlock Text="{Binding ElementName=OptionButton, Path=IsMouseOver}" />
</StackPanel>
</Border>
</Window>
<UserControl x:Name="_this" x:Class="WPFTest.TestUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</UserControl.Resources>
<StackPanel>
<TextBlock Text="SomeText" />
<TextBlock Text="{Binding ElementName=_this, Path=IsMouseOver}" />
<Button x:Name="_cancelTextBlock" Content="Cancel" Visibility="{Binding ElementName=_this, Path=IsMouseOver, Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</UserControl>
After the event is handled by the RadioButton , it is only set as handled but in reality it still bubbles up. So you just need to specify that you want to handle handled events too.
For that you need to look at handledEventsToo.
Unfortunately I don't think it can be set in xaml. only code.
I seemed to have fixed the problem by setting a trigger in the control template, which binds to the RadioButton's IsMouseOver, and sets a custom DependencyProperty on the UserControl.
Something like:
<ControlTemplate TargetType="{x:Type RadioButton}">
<WPFTest:TestUC x:Name="UC" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ShowCancel" Value="True" TargetName="UC"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I'm still confused as to why the Mouse Capture falsifies IsMouseOver on the UserControl child of the RadioButton however. Can anyone shed some light on this?
Very interesting problem. I myself would like to know more of why the UserControl IsMouseOver changes to false when the TextBlock(s) in its visuals are mouse downed upon.
However, here is another way to solve it ... maybe you will like this approach better.
Instead of using RadioButton (since you are retemplating it) why don't you just use Control? (I think IsMouseOver is getting changed to false due to the fact that it is a Button derived control.)
Following is the xaml for the Window ...
<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1"
Width="300"
Height="300"
>
<Window.Resources>
<Style TargetType="{x:Type Control}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Control}">
<local:UserControl1/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Border BorderBrush="Black" BorderThickness="2">
<StackPanel>
<Control x:Name="OptionButton" Height="100"/>
<TextBlock Text="{Binding ElementName=OptionButton, Path=IsMouseOver}"/>
</StackPanel>
</Border>
</Window>
EDIT:
I just wanted to add ... that if you're okay with the above approach ... then, the right thing to do is probably to just use the UserControl in the Window's visual tree versus retemplating a Control. So ... like this:
<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1"
Width="300"
Height="300"
>
<Border BorderBrush="Black" BorderThickness="2">
<StackPanel>
<local:UserControl1 x:Name="OptionButton" Height="100"/>
<TextBlock Text="{Binding ElementName=OptionButton, Path=IsMouseOver}"/>
</StackPanel>
</Border>
</Window>

Resources