I want to synchronize the background of two TextBlockes. For example, if the mouse is over any of the textblockes, I'd like to change the background color to the same for both textblockes. I know I can use this trigger to change one background:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="LightGray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
But how to sync them?
UPDATE: this is not working either:
<UserControl.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="LightGray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Background="{Binding Path=Background, ElementName=tbHeader, Mode=TwoWay}" Text="A"/>
<TextBlock x:Name="tbHeader" Grid.Column="1" Text="B"/>
</Grid>
You can sync it by placing them in ContentControl and applying trigger on ControlTemplate like this -
<Grid>
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<StackPanel>
<TextBlock Text="Rohit" x:Name="txt1"/>
<TextBlock Text="Vats" x:Name="txt2"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="TextBlock.IsMouseOver" SourceName="txt1"
Value="True">
<Setter Property="TextBlock.Background" Value="Red"
TargetName="txt1"/>
<Setter Property="TextBlock.Background" Value="Red"
TargetName="txt2"/>
</Trigger>
<Trigger Property="TextBlock.IsMouseOver" SourceName="txt2"
Value="True">
<Setter Property="TextBlock.Background" Value="Red"
TargetName="txt1"/>
<Setter Property="TextBlock.Background" Value="Red"
TargetName="txt2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
</Grid>
Try element to element binding
<TextBlock x:Name=textBlock1>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="LightGray"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Background={Binding Path=Background ElementName=textBlock1/><!--Background gets set from textBlock1-->
If you are looking for the 'correct' MVVM way, you should bind the mouse-over events/properties to the same property of a view model, and the background to the same property again, with a converter to convert it to the appropriate colour (or a style with templates).
Related
I want to achieve similar effect, which can be seen in Notepad++: dividing TabContol into two TabControls. Obviously both will have selected tab on their own, but still only one of them will be active.
For those who doesn't know Notepad++, this is how it looks like:
For that I'll need to introduce "Active" property on TabControl (not Focused, because when one of TabControls loses focus, its selected tab still remains active). However, I have no idea how to craft trigger on TabItem's ControlTemplate, which will allow me to distinguish selected and selected+active tab.
This is how my current TabItem template look:
<Style x:Key="BaseRootTabItem" TargetType="TabItem">
<Style.Setters>
<Setter Property="Background" Value="{StaticResource NormalTabBackgroundBrush}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource NormalTabForegroundBrush}" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter Property="Background" Value="{StaticResource HoverTabBackgroundBrush}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource HoverTabForegroundBrush}" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="DocumentTabItem" TargetType="TabItem" BasedOn="{StaticResource BaseRootTabItem}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border x:Name="TabBorder" BorderThickness="1,1,1,0" BorderBrush="Transparent"
Background="{TemplateBinding Background}" TextBlock.Foreground="{TemplateBinding Foreground}">
<ContentPresenter x:Name="ContentSite" HorizontalAlignment="Center" VerticalAlignment="Center" ContentSource="Header" Margin="6,2" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Background" Value="{StaticResource SelectedDocumentTabBackgroundBrush}" />
<Setter Property="Foreground" Value="{StaticResource SelectedDocumentTabForegroundBrush}" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
I need something like:
<Trigger Property="(Owning TabControlEx's Active property)" Value="True">
<Trigger.Setters>
...
</Trigger.Setters>
</Trigger>
Or maybe there's some other solution?
Since Active property doesn't belong to TabItem, Trigger won't work. Use DataTrigger with binding to parent:
<DataTrigger Binding="{Binding Active, RelativeSource={RelativeSource AncestorType=TabControlEx}}"
Value="True">
</DataTrigger>
I've been struggeling with this issue today when as soon as I try to bind a data trigger on a button I get this issue and I can't find our the issue. The button is contained in a listview which is bound to a dataset.
There is my button code:
<Button
Grid.Row="1"
Grid.Column="0"
Click="BtnAddToCart_Click"
MinWidth="230">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Margin" Value="7,5,0,0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OrderQty, Converter={StaticResource GreaterThanZero}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate>
<WrapPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<WrapPanel.Style>
<Style TargetType="{x:Type WrapPanel}">
<Setter Property="Background" Value="#ec3c42"/>
<Setter Property="TextBlock.Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Cursor" Value="Hand"></Setter>
<Setter Property="TextBlock.Foreground" Value="#ec3c42"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</WrapPanel.Style>
<WrapPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Padding" Value="10,10" />
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="15"/>
</Style>
</WrapPanel.Resources>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="Ajouter aux Commandes"></TextBlock>
<fa:FontAwesome Visibility="Hidden" VerticalAlignment="Center" HorizontalAlignment="Right" Icon="check">
<fa:FontAwesome.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</fa:FontAwesome.Triggers>
</fa:FontAwesome>
</WrapPanel>
</ControlTemplate>
</Button.Template>
</Button>
The issue seems to happen when I add this piece of code:
<fa:FontAwesome.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</fa:FontAwesome.Triggers>
When I remove the trigger the code run as expected.
Even when I bind it to a property that is working on a different level it doesn't work.
I tried changing the binding to:
Binding="{Binding Path=OrderQty, Converter={StaticResource GreaterThanZero}}
and it's still giving me the error. I tried to look up some code example but didn't find anything about that issue (since the error is pretty common it's hard to tell what is going on).
Try
<fa:FontAwesome Visibility="Hidden" VerticalAlignment="Center" HorizontalAlignment="Right" Icon="check">
<fa:FontAwesome.Style>
<Style TargetType="fa:FontAwesome">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</fa:FontAwesome.Style>
</fa:FontAwesome>
I would like to change the TabItem's Header FontWeight to Bold when IsSelected = True from my ResourceDictionary.
Some Code
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Background="White"
BorderBrush="White"
BorderThickness="1,1,1,0"
Margin="0,0,0,-1" >
<ContentPresenter x:Name="ContentSite"
Height="25"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#F2F1F0" />
<Setter TargetName="Border" Property="BorderBrush" Value="Gray" />
<Setter TargetName="Border" Property="BorderThickness" Value="0.5,0.7,0.5,0" />
<Setter Property="Header">
<Setter.Value>
<TextBlock Text="{Binding Path=Header.Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"
FontWeight="Bold" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="White" />
<Setter TargetName="Border" Property="BorderBrush" Value="Gray" />
<Setter TargetName="Border" Property="BorderThickness" Value="0,0,0,0.5" />
</Trigger>
.....etc.....
The above approach doesn't work. Also setting the HeaderTemplate instead of Header it works but it ruins my template. Finally, setting the TextBlock.FontWeight as a Property inside the Trigger changes all the TextBlocks inside the TabItem.
Any Proposals?
UPDATE
I picked up #ShineKing answer because it helped me solve my problem. Basically what i did is add a DataTrigger to the TextBlock used as a Header to my "custom" TabItem.
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
Could you try this code to change TextBlock as Bold
<TabControl>
<TabControl.Resources>
<Style TargetType="TextBlock" x:Key="HeaderTextBlockStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=TabItem}}"
Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TabControl.Resources>
<TabItem>
<TabItem.Header>
<TextBlock Text="Header Text"
Style="{StaticResource HeaderTextBlockStyle}"/>
</TabItem.Header>
</TabItem>
</TabControl>
I am trying to style my WPF TabControl. I basically want to get the tab control to have a transparent background, with a white border and text. I want the selected tab to have a White Background and Transparent Text (or any colour text!). Essentially a 2 colour tab.
However, I cannot override the selected tab appearance - this shows as white. And my child textboxes are taking the style of the TabItem font. Note, in the screen shot my labels have their own style set so do not take the TabItem font.
I have the following XAML in place to do this. Ideally I want to create the styles so that I can reuse across the application.
Resource Dictionary
<ResourceDictionary 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">
<Style x:Key="Tabs" TargetType="TabControl">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="White"/>
</Style>
<Style x:Key="TabItemStyle" TargetType="TabItem">
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Background" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TabItem}}" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Then the XAML MarkUp
<TabControl Style="{StaticResource Tabs}">
<TabItem Header="General" Style="{StaticResource TabItemStyle}">...</TabItem>
<TabItem Header="Details" Style="{StaticResource TabItemStyle}">...</TabItem>
<TabItem Header="Info" Style="{StaticResource TabItemStyle}">...</TabItem>
<TabItem Header="More Stuff..." Style="{StaticResource TabItemStyle}">...</TabItem>
</TabControl>
How can I style my tabs to be and prevent the children from sizing?
Your DataTriggers don't work. To fix it change RelatveSource to Self
Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}"
However I would suggest to change them to Triggers like so:
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Background" Value="White"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Foreground" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
You should create control template for TabItem.
This sample change TabItem background to Transparent and Text color to White.
You can use own color schema.
<Window.Resources>
<Style TargetType="TabControl">
<Setter Property="Background"
Value="Transparent" />
<Setter Property="BorderBrush"
Value="White" />
</Style>
<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="{x:Static Brushes.White}"
BorderBrush="{x:Static Brushes.White}"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0">
<ContentPresenter x:Name="ContentSite"
Margin="12,2,12,2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header"
RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Panel.ZIndex"
Value="100" />
<Setter TargetName="Border"
Property="Background"
Value="{x:Static Brushes.Transparent}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="1,1,1,0" />
<Setter Property="TextBlock.Foreground"
Value="White" />
<!--<Setter Property="TextBlock.Foreground"
Value="Transparent" />-->
</Trigger>
<Trigger Property="IsEnabled"
Value="False">
<Setter TargetName="Border"
Property="Background"
Value="{x:Static Brushes.White}" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="{x:Static Brushes.White}" />
<Setter Property="Foreground"
Value="{x:Static Brushes.White}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Background="SkyBlue">
<TabControl Margin="20">
<TabItem Header="TabItem #1">
<TextBox>Tab Item #1 content</TextBox>
</TabItem>
<TabItem Header="TabItem #2">
<TextBox>Tab Item #1 content</TextBox>
</TabItem>
<TabItem Header="TabItem #3">
<TextBox>Tab Item #1 content</TextBox>
</TabItem>
</TabControl>
</Grid>
The Problem: In BarCheckItem, if BarCheckItem IsChecked, how do I style a border inside its DataTemplate?
I'm styling a BarCheckItem. To do it, I added a ContentTemplate with a DataTemplate inside where I added some color borders that change on MouseOver:
<dxb:BarCheckItem Name="barCheckItemRecord"
Command="..."
Cursor="Hand"
IsChecked="..."
IsVisible="..." >
<dxb:BarCheckItem.ContentTemplate>
<DataTemplate>
<StackPanel>
<Border x:Name="audioButtonInnerBorderLight">
<Canvas .../>
</Border>
</StackPanel>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="audioButtonInnerBorderLight" Property="Background" Value="#30FFFFFF" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</dxb:BarCheckItem.ContentTemplate>
</dxb:BarCheckItem>
What I want to do now is to change the color of the border when the BarCheckItem is IsChecked.
Problem is, I only know how to use the triggers in a style, like this:
<dxb:BarCheckItem Name="barCheckItemRecord" [all the code from above]>
...
<dxb:BarCheckItem.Style>
<Style TargetType="{x:Type dxb:BarCheckItem}">
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Blue" />
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter Property="Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</dxb:BarCheckItem.Style>
</dxb:BarCheckItem>
But I don't know how to point to the border (x:Name="audioButtonInnerBorderLight") FROM the triggers. Because the triggers don't know where the border is.
How can I make something like the following work?:
<Style TargetType="{x:Type dxb:BarCheckItem}">
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="audioButtonInnerBorderLight" Property="Background" Value="Purple" />
</Trigger>
</Style>
Note: I thought the best idea was to put the border in a ContentTemplate in the BarCheckItem, using a Template setter. But it looks like BarCheckItems don't allow Templating.
You sholud add those triggers to the DataTemplate :
<dxb:BarCheckItem Name="barCheckItemRecord"
Command="..."
Cursor="Hand"
IsChecked="..."
IsVisible="..." >
<dxb:BarCheckItem.ContentTemplate>
<DataTemplate>
<StackPanel>
<Border x:Name="audioButtonInnerBorderLight">
<Canvas .../>
</Border>
</StackPanel>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="audioButtonInnerBorderLight" Property="Background" Value="#30FFFFFF" />
</Trigger>
<DataTrigger Binding="{Binding Path=IsChecked,RelativeSource={RelativeSource AncestorType={x:Type dxb:BarCheckItem}}}" Value="True">
<Setter TargetName="audioButtonInnerBorderLight" Property="Background" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsChecked,RelativeSource={RelativeSource AncestorType={x:Type dxb:BarCheckItem}}}" Value="{x:Null}">
<Setter TargetName="audioButtonInnerBorderLight" Property="Background" Value="Yellow" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</dxb:BarCheckItem.ContentTemplate>
</dxb:BarCheckItem>
I finally found the best way to do this.
What I did was adding the ContentTemplate in the styles, and use the triggers from there:
<dxb:BarCheckItem ...>
<dxb:BarCheckItem.Style>
<Style TargetType="{x:Type dxb:BarCheckItem}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Border x:Name="audioButtonInnerBorderLight">
<Canvas .../>
</Border>
</StackPanel>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="audioButtonInnerBorderDark" Property="Background" Value="#30FFFFFF" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Border x:Name="audioButtonInnerBorderCHECKED">
<Canvas .../> (different styles here)
</Border>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</dxb:BarCheckItem.Style>
</dxb:BarCheckItem>