TextBlock Vs ContentControl in performance in XAML - wpf

I have a section header which contains two words to be displayed in XAML with a little bit of style with fontsize and fontfamily. I can implement this with TextBlock or ContentControl (by setting the content property to the header text).
The TextBlock is not derived from Control, so is the intent of TextBlock to perform better in XAML for text compared to a contentcontrol?

Your TextBlock is just that, a TextBlock as framework element when you invoke it is just an object. So when you write <TextBlock Text="Blah Blah Blah"/> that's literally all it is.
When you're using a ContentControl you're actually invoking a templated control that will have multiple elements in its tree that are added for every instance. So example you're using;
<Style TargetType="ContentControl">
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So a short version to your answer would be Yes, TextBlock will perform better and is suggested to be used over templated controls like ContentControl or Label etc. wherever possible.
Hope this helps, cheers.

To directly answer your question -- if your intent is to only always render text, yes, use only a TextBlock. As others have pointed out using a ContentControl/ContentPresenter and setting to a string will wrap it anyway, and you have increased your element count +1 unnecessarily.

Related

Foreground does not apply for labels

I have some labels like this:
<Label x:Name="ledCalculate" Width="Auto" Content="Calculate" Height="25" FontFamily="Cambria" FontSize="18.667" VerticalContentAlignment="Bottom" Padding="10,0,0,0" BorderThickness="0,0,0,1" Style="{StaticResource RightPanelLabels}" Grid.Row="11"/>
I defined a style for it:
<Style TargetType="Label" x:Key="RightPanelLabels" BasedOn="{StaticResource
{x:Type Label } }">
<Setter Property="Foreground" Value="#FFEABEBE"></Setter>
<Setter Property="BorderBrush" Value="#FF818080"></Setter>
<Setter Property="BorderThickness" Value="0,0,0,1"></Setter>
</Style>
Border thickness setter in style applies for control and it has upper precedence in style, and visual studio ignores its values in local, but foreground setter in style does not applies, when i set it locally it applies,
Why border thickness in style have upper precedence but foreground in local have upper precedence????????
I know there is a default template for labels like bellow that have a trigger for IsEnabled , that template is something like this:
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" 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>
Can anyone help me?
Sorry for my English.
All the local styles take precedence over defined styles, so inline styles will always override other styles defined in resources.
When I run the code I found that Style's BorderThickness also get overridden by the local inline style value for BorderThickness as well.
I too would love to hear if there's a workaround for this.
I found this article as well, hope it helps Same problem with a style trigger though
EDIT:
Upon trying it few different ways I found using this method we can override the label's inline Foreground style, but I don't know whether it's the healthiest way
<Style TargetType="{x:Type Label}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}"
Foreground="Red" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Label FontSize="50" Foreground="Black"> I am Black inline, Red on Style </Label>
This is me just editing the ContentTemplate of the Label .
Basically, this possible for Label because Label derives from ContentControl whereas TextBlock lives in the System.Windows.Controls namespace, it is not a control. It derives directly from FrameworkElement.
TextBlock are used in many other controls to show texts, including in Label.
Refer this article to know more about this
you have to change property name in style setter
<Setter Property="TextBlock.Foreground" Value="#FFEABEBE">

Stop button color change on Mouseover

ok..this is very strange....i have defined a button, actually 5 buttons and each have a different color but on mouse over, they just change the color to that icy blue color....i tried to override that by using the below code :
<Button Name="btn1" Content="Button" Width="65" Height="45" Background="Green" Margin="1,1,0,1" FontWeight="Bold">
<Button.Style>
<Style>
<Style.Triggers>
<Trigger Property="Button.IsMouseOver" Value="True">
<Setter Property="Button.Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.LayoutTransform>
<RotateTransform Angle="270"/>
</Button.LayoutTransform>
</Button>
but it still does not work...what i want is that it should maintain the background color it has been given(different for each button), so the question is : do i have to define it again and again for each button (the trigger did not work, color becomes ice blue) OR can i define it in the resource file with a generic value that it either stops the color change or just sets background to existing property
EDIT : Just to be clear, i want the button to stop changing its color on mouseover and just retain whatever color i have assigned it.....
Based on the comments and the SO post I linked: that article applied the style to anything of type Button, that's why it applies to all buttons (which is not necessarily a bad thing). But the salient point to take away from that article is that what you need to modify is the ControlTemplate.
So you would want to do something like this:
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Chrome" BorderBrush="Black" BorderThickness="2" CornerRadius="2" Background="{TemplateBinding Property=Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
This isn't perfect, because it loses all of it's interactivity (ie. you can't tell you've pushed it, hovered over it or anything). But it gives you a good starting point.
One of the key points here is that the Background property of the Border is bound to the TemplateParent Property=Background, that means it's going to read the background property of the button the that it is templating and use it's background color. This makes it easier for you to use a single style to cover all 5 of your buttons. You could (and may want to) do similar things with the BorderBrush property.
Also notice my style has a x:Key value, so in order to use this, you would do:
<Button x:Name="btn1" Content="Button" Width="65" Height="45" Background="Green" Margin="1,1,0,1" FontWeight="Bold" Style="{DynamicResource ButtonStyle1}">
<Button.LayoutTransform>
<RotateTransform Angle="270"/>
</Button.LayoutTransform>
</Button>
You can remove the x:Key attribute and the style will indeed apply to all buttons inside of whichever container you declare the resource.

Image Button only responds when clicking on the image and not the area around inside the button

I'm using the following button style which takes away the borders and makes a transparent background to make my image buttons:
<Style x:Key="EmptyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#00000000"/>
<Setter Property="BorderBrush" Value="#00000000"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<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}">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The Style is from the following answer:
WPF button with image of a circle
The problem now is that the clickable area is confined to the image regardless of how big the actual button is:
My button code:
<Button Name="n02" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Style="{DynamicResource EmptyButtonStyle}" Canvas.Left="308" Canvas.Top="157" Height="106" Width="120">
<Image Source="boto_face_off.PNG" Height="61" Width="59" />
</Button>
Question: how do I make the whole button area react to the click? I want to keep it transparent and without border as it is now.
You could wrap the presenter in a Border with a bound Background.
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<!-- ContentPresenter here -->
</Border>
</ControlTemplate>
The style sets the Background to something transparent but it was never even used in the Template, this way the Border will make the whole area hit-test.
Just adding some info to the answer above after investigating the issue for hours.
If you are defining your own template as in the example above you are changing the visual tree of the element. In the above example applying the Style="{DynamicResource EmptyButtonStyle}" it becomes:
Button
|
ContentPresenter
But if you look at the visual tree of a standard button(you can do this in Visual Studio) it looks like this:
Button
|
ButtonChrome
|
ContentPresenter
So in the styled button there is nothing around the ContentPresenter to be clicked on, and if the Content is in the "middle" the surrounding area will be left totally empty. We have to add an element to take this place:
You can do it with a <Border>(I think this is best because Border is a lightweight element I suppose) or some other element, I tried <Grid> and <DockPanel> and both worked.
The only thing I don't understand is why you need to explicitly set the background to something transparent, just leaving it out will not produce a clickable area.
Edit: Last point answered in the comments here Image Button only responds when clicking on the image and not the area around inside the button
I have Button where content is Grid containing Image and TextBlock
I fixed clickable area by adding Transparent Background to grid
Background="#00000000"

Datagrid checkbox styling

Hello
First sorry for my english.
I have started recently my first project on wpf. I´m styling a custom DataGrid who have been defined programatically (the xaml code doesn´t exists).
I have styled all that i need in my datagrid control except a checkbox that i wrapped inside.
The problem is that in other place of my application i defined a checkbox style how are applying correctly but i can´t apply inside my datagrid.
Actually my datagrid doesn´t throw syntax errors but when the datagrid runs the checkbox styles doesn´t apply.
The style code look like this (its defined in a stylesheet)
... <Setter Property="DataGridCheckBoxColumn.ElementStyle">
<Setter.Value>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent">
<BulletDecorator.Bullet>
<Grid Width="13" Height="13">
<Border x:Name="Border" Background="Pink" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="2,2,2,2"/>
<Path x:Name="CheckMark" Stroke="Green" StrokeThickness="2" SnapsToDevicePixels="False" Data="M1.5000001,1.5833334 L9.7920001,9.6666667 M1.5420001,9.6666667 L9.7083333,1.5000001" Margin="1" ClipToBounds="False" StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
</Grid>
</BulletDecorator.Bullet>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</BulletDecorator>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>...
Its exactly the same that it`s applying in the apliccation.
I´ve read a lot about it but i can´t to apply it, i tried, also, setting the setter property to "DatagridBoundColum.ElementStyle" and also to "CellStyle" but it doesn´t work.
Any suggest??
Thank a lot.
Do it like you would do in xaml:
<UserControl.Resources>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox Style="{StaticResource AnyResourceKeyInApplciation}"/>
</DataTemplate>
</UserControl.Resources>
<DataGrid x:Name="dataGrid" />
this.dataGrid.Columns.Add(new DataGridTemplateColumn
{
CellTemplate = this.Resources["CheckBoxTemplate"] as DataTemplate
}
);
Thanks for your Reply vorrtex.
I didn´t apply it exactly but it helped me to find the solution, however i would have liked not to modify the VB code and only to modify it the xaml style tag.
I find an object how simplify this task. The syntax it´s the following:
column2.ElementStyle = Application.Current.FindResource("CheckBoxStyle")
It´s applying style ok inside the datagrid. But actually it´s placing at left border of the cell. I´ll try to find why.
Thanks again.
You can try this
<Controls:DataGridCheckBoxColumn Header="Homme" Binding="{Binding Homme}">
<Controls:DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="4,0,0,0"/>
</Style>
</Controls:DataGridCheckBoxColumn.ElementStyle>
</Controls:DataGridCheckBoxColumn>

DataTemplate / ContentTemplate - exchange controls

How can i solve the following (simplified) problem?
M-V-VM context. I want to show text at the UI.
In case the user has the rights to change the text, i want to use a textbox to manipulate the text.
In case the user has no rights, i want to use a label to only show the text.
My main problem: how to exchange textbox and label and bind Text resp. Content to the same property in viewmodel.
Thanks for your answers
Toni
There are a few ways of achieving this, with varying degrees of ease of reuse. You can have a DataTemplateSelector that could return the appropriate DataTemplate for a given property (depending on how this is written, you may be able to use it for each of your properties).
You could create a DataTemplate for each property, and change visibility based on a DataTrigger (this gets really annoying, as it is a lot of copy and paste).
I think the easiest way of doing this is with a specialized ControlTemplate for the TextBox. Basically, when it is disabled, instead of graying it out, you can just make it look like a TextBlock:
<ControlTemplate x:Key="PermissionedTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bd" Property="BorderBrush" Value="{x:Null}" />
<Setter TargetName="bd" Property="Background" Value="{x:Null}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Then you can use it like so:
<TextBox Text="{Binding PermissionedText}" IsEnabled="{Binding CanEdit}" />

Resources