wpf property inheritance - wpf

I want ask a question about that code its simple XAML code as show as below.
<Window x:Class="WpfApplication15.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" Background="Orange" FontStyle="Italic">
<StackPanel>
<Label>blo</Label>
<Button>hi</Button>
<Button>hi2</Button>
</StackPanel>
</Window>
So simply we can imagine, labels background orange but background color of button wont be orange will be as default, but all controls FontStyle will be italic, so question is that! why fontstyle of all control under root affected that but button's background doesn't??

I suppose that the ControlTemplate of the button sets the Background-brush explicitely in respect to windows ui-guidelines. Therefore property-inheritance is broken for the Control.BackgroundProperty.
To prove it, maybe this tool will help.

This is the definition of the default button template , Microsoft_Windows_Themes:ButtonChrome is doing the trick
<ControlTemplate TargetType="{x:Type Button}">
<Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
</Microsoft_Windows_Themes:ButtonChrome>

Related

WPF LayoutTransform: ToolTip size not modified

I'm using LayoutTransform in my windows' top level 'Grid' control, to do perform a ScaleTransform and implement a zoom factor on the UI (similar to how browsers do it).
Things work well, but somehow tooltips show up with the unadjusted size.
If there a way to for example enumerate all toolTips in a window and adjust their size from the .cs file? ...or any other way to deal with this?
The reason why the tooltips are unaffected is because tooltips are popups that are not part of the window's visual tree. Thus, any layout transformation performed on the componenets of the window will not carry over to the tooltips. If you have mostly generic tooltips (text basically), you can create a non-keyed style in your window resources and WPF will automatically apply that to all your tooltips:
<Window.Resources>
<Style TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Border.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleFactor}"></ScaleTransform>
</Border.LayoutTransform>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel x:Name="MainPanel">
<StackPanel.LayoutTransform>
<ScaleTransform ScaleX="{Binding ScaleFactor}" ScaleY="{Binding ScaleFactor}"></ScaleTransform>
</StackPanel.LayoutTransform>
<TextBlock ToolTip="blah">haha!</TextBlock>
</StackPanel>
In the example I have ScaleX/Y for the tooltip bound to a ScaleFactor property on my window's View Model. You can keep it dynamic this way I believe.
Like what Rowbear has mentioned, Tooltips are popups (which are windows), so they have their own visual tree. But, as far as I know, the big problem is, these popups do not inherit DataContext from the spawning control, too.
<Window.Resources>
<Style TargetType="ToolTip">
<Setter Property="LayoutTransform" Value="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.LayoutTransform}" />
</Style>
</Window.Resources>

Resize container without resizing text controls

I have a Custom Control containing a Canvas placed inside a Viewbox. This allows me to resize the control and everything inside the Canvas scales beautifully.
Much to my annoyance a requirement to stop any scaling of text within the control has reared its head. All other controls (mainly graphics) should scale, but not text. Text should move to the correct place upon resize, but the font should remain the same.
Any ideas how to do this?
After much head scratching I found a relatively simple workaround.
As I'm not going to need to click on any text in the control I've put all graphics inside one canvas with zOrder 1 and all text in another with zorder 0. Then I put them inside a grid so they overlap:
<ControlTemplate TargetType="{x:Type local:ContourPlot}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Viewbox>
<Border BorderBrush="Black" BorderThickness="1">
<Canvas x:Name="cvGraph" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
<Rectangle Canvas.Left="40" Canvas.Top="31" Width="48" Height="41" Fill="AliceBlue"/>
</Canvas>
</Border>
</Viewbox>
<Canvas Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
<Label x:Name="lblTest" Canvas.Left="0" Canvas.Top="10" Content="Label" FontSize="12" />
</Canvas>
</Grid>
</Border>
</ControlTemplate>

Aligning Text with a ContentControl using the HorizontalContentAlignment property

I am attempting to apply a "text alignment" to a ContentControl. Since the ContentControl does not have a horizontal or vertical text alignment property like the TextBlock, I am attempting to use the ContentControl's HorizontalContentAlignment property.
My problem is that I can't get it to work with a ContentControl itself.
In my example, I have a content control displaying "hello world" and a button displaying "change it".
When I click the button, I set the HorizontalContentAlignment on the content control and on the button. The button's content changes, but the content control's content does not.
Here is my XAML code:
<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">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ContentControl x:Name="ctrl" Width="525">
Hello World!
</ContentControl>
<Button x:Name="btn" Grid.Row="1" Content="Change It" Click="btn_Click"/>
</Grid>
</Window>
And here is my VB.NET code for the button click event:
Class MainWindow
Private Sub btn_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
If (ctrl.HorizontalContentAlignment = HorizontalAlignment.Left) Then
ctrl.HorizontalContentAlignment = HorizontalAlignment.Right
btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Right
Else
ctrl.HorizontalContentAlignment = HorizontalAlignment.Left
btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Left
End If
ctrl.UpdateLayout()
End Sub
End Class
I am unable to replace my content controls with text blocks for various reasons, but I still need to be able to align the content.
EDIT:
While Narohi work around suggestion works, I am still confused about why the content control's HorizontalContentAlignment property doesn't align the content.
I tried a Label control (which inherits from ContentControl) and it's HorizontalContentAlignment property properly aligns the content.
(Edit again: I am no longer confused about this, it seems that the HorizontalContentAlignment isn't utilized properly in all cases.)
Here is my updated XAML code:
<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">
<Window.Resources>
<ControlTemplate x:Key="AlignmentAwareControl" TargetType="ContentControl">
<ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ContentControl x:Name="ctrlTxt" Grid.Row="0"
Template="{StaticResource AlignmentAwareControl}"
HorizontalContentAlignment="Center" Padding="0">Hello World Content Control!</ContentControl>
<Label x:Name="ctrl" Grid.Row="1" HorizontalContentAlignment="Center" Padding="0">Hello World Label!</Label>
<ContentControl x:Name="ctrlImg" Grid.Row="2"
Template="{StaticResource AlignmentAwareControl}"
HorizontalContentAlignment="Center">
<Image Source="C:\Users\Frinavale\Pictures\Business_Woman.jpg"/>
</ContentControl>
<Button x:Name="btn" Grid.Row="3" Content="Change It" Click="btn_Click"/>
</Grid>
</Window>
Here is my updated VB.NET code:
Class MainWindow
Private Sub btn_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
If (ctrl.HorizontalContentAlignment = HorizontalAlignment.Left) Then
ctrlImg.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
ctrlTxt.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
ctrl.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Right
Else
ctrlImg.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
ctrlTxt.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
ctrl.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Left
End If
ctrl.UpdateLayout()
End Sub
End Class
I'm looking forward to your advice,
-Frinny
Opening up the default control template for ContentControl in Blend reveals why your original approach did not work.
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter/>
</ControlTemplate>
The default template does nothing with the HorizontalContentAlignment property which it inherited from Control. Juxtapose this with Label's default template.
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
As we can see, the Label actually binds to the HorizontalContentAlignment. WPF controls are lookless, so there is never a guarantee that a property will be respected by the current ControlTemplate. I would speculate that the WPF designers didn't respect the HorizontalContentAlignment property because people usually place content within that is independent of the ContentControl's properties or perhaps they assumed if someone was going to use such a generic control they would provide their own template, such as...
<ContentControl x:Name="ctrl" Width="525">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Grid>
</ControlTemplate>
</ContentControl.Template>
Hello World!
</ContentControl>

Silverlight: Button template with texttrimming cut off

I'm replacing the default Button template's ContentPresenter with a TextBlock, so the text can be trimmed when it's too long.
Works fine in WPF. In Silverlight the text gets pushed to one edge and cut off on the left, even when there's space on the right:
Template is nothing special, just replaced the ContentPresenter with the TextBlock:
<Border x:Name="bdrBackground"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" />
<Rectangle x:Name="rectMouseOverVisualElement"
Opacity="0">
<Rectangle.Fill>
<SolidColorBrush x:Name="rectMouseOverColor"
Color="{StaticResource MouseOverItemBgColor}"/>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="rectPressedVisualElement"
Opacity="0"
Style="{TemplateBinding Tag}"/>
<TextBlock x:Name="textblock"
Text="{TemplateBinding Content}"
TextTrimming="WordEllipsis"
TextWrapping="NoWrap"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Rectangle x:Name="rectDisabledVisualElement"
Opacity="0"
Style="{StaticResource RectangleDisabledStyle}"/>
<Rectangle x:Name="rectFocusVisualElement"
Opacity="0"
Style="{StaticResource RectangleFocusStyle}"/>
</Grid>
</ControlTemplate>
How do I fix this?
More info:
With the latest comment about HorizontalAlignment, it's clear that SL's implementation of TextTrimming differs from WPF's. In SL, TextTrimming only really works if the text is aligned left. SL isn't smart enough to align the text the way WPF does. For instance:
WPF button:
SL button with the textblock horizontalalignment = left:
SL button with textblock horizontalalignment = center:
There's an even simpler solution. I set the TextBlock's TextAlignment=Center. Works exactly like in WPF. Thanks for the help!
The problem will be that your HorizontalContentAlignment is set to "Center". Really WordEllipsis only makes sense when the HorizontalAlignment of the TextBlock is set to "Left".
Edit
Getting the desired behaviour try this:-
<Border HorizontalAlignment="Center"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<TextBlock x:Name="textblock"
Text="{TemplateBinding Content}"
TextTrimming="WordEllipsis"
TextWrapping="NoWrap"
Margin="{TemplateBinding Padding}" />
</Border>

Silverlight - use a ScrollViewer in a TextBox template

I'm trying to make a TextBox template and I need to include a ScrollViewer in the template - basically I want to add some content (like line numbers) that needs to scroll along with the normal text.
The default template for the TextBox is like this:
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="1" Opacity="1">
<Grid>
<Border x:Name="ReadOnlyVisualElement" Background="#5EC9C9C9" Opacity="0"/>
<Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
<ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
</Border>
</Grid>
</Border>
If I change the ContentElement from ScrollViewer to Border, for example, the TextBox behaves normally - i just lose the scrolling ability.
Now, if I wrap the ContentElement with a ScrollViewer, it no longer displays the caret and selection - if you type, it still gets updated though.
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="1" Opacity="1">
<Grid>
<Border x:Name="ReadOnlyVisualElement" Background="#5EC9C9C9" Opacity="0"/>
<Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<Border x:Name="ContentElement" BorderThickness="0" Padding="{TemplateBinding Padding}" />
</ScrollViewer>
</Border>
</Grid>
</Border>
Any idea why this happens and how can I fix it?
Just a shot in the dark, as I have not verified...but the control may be looking for a TemplatePart named ContentElement of type ScrollViewer.

Resources