style textblock button change text - wpf

I want to change the TextBlock of a button programatically, but I still didn't get it right.
<Style x:Key="RoundedButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="50" Background="#463190">
<TextBlock Text="{Binding Tag}" Foreground="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0,0,0,0"
FontSize="20"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Button controls has a property Content to show texts and no need to use Tag. It makes things are more complex.
If you change your Binding to the below, you will be able to use Button's Content property to change the Text inside the TextBlock.
Text = "{Binding Path=Content,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"

Related

How to change the custom content of a ToggleButton in XAML

I have changed the style of a ToggleButton in a ResourceDictionary. In my style I'm changing the ControlTemplate of the ToggleButton and I place an image before the Content.
Now here is my question: The image needs to be changed for different ToggleButtons I use in XAML, should I define different styles for each ToggleButton with different image or is there some way I can change its image in XAML?
<Style x:Key="BaseToggleButton" TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<StackPanel Orientation="Horizontal" x:Name="Border">
<Image Width="13" Height="13" Source="{StaticResource ColumnsLayoutMiniIcon}"/>
<TextBlock>
<ContentPresenter/>
</TextBlock>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is there a way I can change the image here instead of in style?
<RadioButton Content="Plan View"
GroupName="View"
Style="{StaticResource BaseToggleButton}">
</RadioButton>
Sure, you can piggy back in on an unused property that comes in real handy for this sort of situation called Tag which you can you use to pass in your image path or resource declaration etc once we go bind it to the template like;
<Style x:Key="BaseToggleButton" TargetType="ToggleButton">
<!-- Let's give it a default -->
<Setter Property="Tag" Value="{StaticResource ColumnsLayoutMiniIcon}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<StackPanel Orientation="Horizontal" x:Name="Border">
<Image Width="13" Height="13"
Source="{TemplateBinding Tag}"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now we can either leave as is and it should display that mini icon as your default, you can specify a new one at the instance level like;
<ToggleButton Content="Plan View"
Tag="{StaticResource ADifferentImagePathOrResourcePointingToOne}"
Style="{StaticResource BaseToggleButton}"/>
Hope this helps, cheers.

wpf mouseover margin in stackpanel

I have a tab item, header having the following form: image_margin_textblock.
The trigger IsMouseOver is working properly when the mouse cursor is over the image, and also over the textblock. But, when the mouse cursor is over the margin between the Image and Textblock, the IsMouseOver trigger is not fired. This creates an annoying flickering effect.
Do you have any ideas how to achieve mouseover trigger over the margin?
Here is the code:
<TabItem.Header>
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<StackPanel x:Name="sp0" Orientation="Horizontal">
<StackPanel x:Name="sp1" Orientation="Horizontal" Background="Blue">
<Image VerticalAlignment="Center" HorizontalAlignment="Center" Source="tab1.png"/>
</StackPanel>
<TextBlock Margin="10,0,0,0" Text="Tab1" VerticalAlignment="Center"/>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" Value="True">
<Setter TargetName="sp1" Property="StackPanel.Background" Value="Green"/>
</DataTrigger>
<Trigger SourceName="sp0" Property="IsMouseOver" Value="True">
<Setter TargetName="sp1" Property="StackPanel.Background" Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Thank you.
Set Background on outer StackPanel to Transparent so that margin also participates in HitTest (i.e. respond to mouse events).
Right now only image and TextBlock area responds to MouseOver event. Setting background to Transparent will work.
<StackPanel x:Name="sp0" Orientation="Horizontal" Background="Transparent">
Set background of your StackPanel to Transparent. This makes it visible to hit test.
<StackPanel x:Name="sp0" Orientation="Horizontal" Background="Transparent">
<StackPanel x:Name="sp1" Orientation="Horizontal" Background="Blue">
<Image VerticalAlignment="Center" HorizontalAlignment="Center" Source="tab1.png"/>
</StackPanel>
<TextBlock Margin="10,0,0,0" Text="Tab1" VerticalAlignment="Center"/>
</StackPanel>

How to make CollectionView grouping respect data template settings

I have ListBox with group style:
<GroupStyle HidesIfEmpty="True" x:Key="GroupStyle">
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
<Expander.Header>
<DockPanel Background="LightSkyBlue"
Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}},
Path=ActualWidth}">
<TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
<TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter/>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
Any change in bound collection causes expanders to reopen.
Is there any way to remember user preferences and leave expanders folded?
The question is what you are doing with the bound collection.
I agree with Nikolay that the best option is to have your viewmodel have a property that you will bind the expander to.
As for the question I've asked at the beginning: Are you somewhat refreshing the CollectionView?
Refresh causes the UI to be recreated. (Meaning, it is like Reset on an ObservableCollection. It tells the UI to create the user controls and load the XAML of your templates again which is bad for performance).
I can suggest a simple hack - just add IsExpanded property to your model class and bind Expander.IsExpanded to it.

getting validation into a style

I use IDataErrorInfo on my viewmodels and I have a style (below) for a TextBox with an error template that works ok. I know that "ValidatesOnDataErrors=True" used like:
<TextBox Text="{Binding Path=LastName, ValidatesOnDataErrors=True}"
Style="{StaticResource TextBoxStyle}" />
will force WPF to use IDataErrorInfo but am wondering how to get that baked into my style.
Cheers,
Berryl
<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
...
<!--
Error handling
-->
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Text=" *"
Foreground="Red"
FontWeight="Bold" FontSize="16"
ToolTip="{Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"/>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="placeholder"></AdornedElementPlaceholder>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="LightYellow"/>
</Trigger>
</Style.Triggers>
</Style>
If I understand what you're asking, you want to be able to be able to use the ValidatesOnDataError=True in your style, that so you don't have to repeat it every time.
If that's the case you can't, because that is a property of the data binding and not the style; and you can't template the data binding.
I just wonder if you use a Label instead of a TextBox, then in the style of the Label you can probably do something like this,
<ControlTemplate TargetType="sdk:Label">
<TextBlock x:Name="textBlock" Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}, ValidatesOnDataErrors=True}">
You can't because that is part of the definition of the binding to your property, not how the error is visualized.

How can I change the font size of a label in my ControlTemplate

In my WPF ListBox, I have a style with a ControlTemplate for a ListBoxItem. Inside that ControlTemplate I have a label defined. Based on some details, I need to change the font size of the label. So from my code-behind, I need to determine what the font should be and then I need to set it.
Here is my style with the ControlTemplate (I've stripped out some irrelevant controls)
<Style x:Key="RecordTabList" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="{DynamicResource RecordIndexTabBackcolor}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Label
x:Name="myLabel" Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1" Margin="3,-2,0,-2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Foreground="{DynamicResource RecordIndexTabForeground}"
FontSize="10" Height="Auto" BorderThickness="3,0,0,0"
Content="{Binding Path=Name}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
How can I do this?
If I understand you correctly, you can probably do something similar to the following, and simply change the FontSize property on the ListBoxItem itself; it will be reflected automatically on your Label. Copy this into VS and see it in action!
<Window.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Label Content="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListBox Margin="12">
<ListBoxItem Content="Test 1" FontSize="14"/>
<ListBoxItem Content="Test 2" FontSize="18"/>
<ListBoxItem Content="Test 3" FontSize="22"/>
</ListBox>
</Grid>
You might be able to use a ValueConverter on the FontSize property.. but I'm not 100% sure if they work inside a ControlTemplate.. I seem to remember Silverlight having issues with it, but I can't remember if it worked in WPF.
If you want to set the FontSize in the code behind, you should remove FontSize from the ControlTemplate, then set it for the ListBoxItem in the code-behind. If you want to set the same size for all the ListBoxItems just set the FontSize of the ListBox in the code-behind.

Resources