Datatrigger in WPF - wpf

I am new to WPF, and learning the basics of WPF. What I want is when a CheckBox is checked then make the background of a Button green.
The following is to code I have written:
<Window x:Class="MyApplication.DataTrigger2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataTrigger2" Height="300" Width="300" Loaded="Window_Loaded">
<Window.Resources>
<Style x:Key="styleDataButton" TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding chk}" Value="checked">
<Setter Property="Background" Value="Gold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Button x:Name="btn" Height="50" Width="100" Content="Button" Margin="89,33,89,178" Style="{StaticResource styleDataButton}"/>
<CheckBox x:Name="chk" Content="Checkbox" Height="50" Width="100" Margin="89,106,89,105"></CheckBox>
</Grid>
</Window>

You need to bind to CheckBox element. Binding="{Binding chk}" means that you are binding to "chk" property of the DataContext. You should change it to:
<DataTrigger Binding="{Binding ElementName=chk, Path=IsChecked}" Value="True">
<Setter Property="Background" Value="Gold"/>
</DataTrigger>
That way, you are binding to IsChecked property of your CheckBox and checking if value is true.

Related

Cannot set trigger within TabControl template in WPF

I wrote a style for my TabControl. Within the TabControl I have a TextBlock and a Button. I wish to set trigger for TabItem.IsSelected such that the font colour of the text within TextBlock changed. My code below doesn't work:
<Style x:Key="_tabItemButtonStyle" BasedOn="{StaticResource MetroTabItem}" TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Name="_TabHeaderStackPanel" >
<TextBlock Text="{ Binding TabName }" Name="_TabHeaderText" Background="{ Binding TabBackColour }" FontSize="{ Binding TabFontSize }" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=TabItem}}"
Value="True">
<Setter Property="Foreground" Value="SteelBlue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
...
The problem I suspect is with this code:
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=TabItem}}"
Value="True">
<Setter Property="Foreground" Value="SteelBlue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
EDIT:
I bind my tab items to a Collection of ViewModels. So my style binding looks as following:
<TabControl x:Name="_MainTabControl" Grid.Column="1" Grid.Row="1"
SelectedIndex="0"
ItemsSource="{Binding OpenTabs}"
ItemContainerStyle="{StaticResource _tabItemButtonStyle}" />
I don't know what MetroTabItem is. But the other Code looks fine.
I tried it out with sample Code. And it does exactly what you describe you want to achieve.
Please check whether your Styles are correctly applied with Style={StaticResource YourStyleName} on the TabItem
Here my XAML:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
</Window.Resources>
<Grid>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="{x:Type TabItem}" x:Key="TestStyle">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Name="_TabHeaderStackPanel" >
<TextBlock Text="test" Name="_TabHeaderText" Background="{ Binding TabBackColour }" FontSize="{ Binding TabFontSize }" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=TabItem}}"
Value="True">
<Setter Property="Foreground" Value="SteelBlue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Button Content="Test"></Button>
</StackPanel></DataTemplate></Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Grid.Resources>
<TabControl>
<TabItem Style="{StaticResource TestStyle}">
</TabItem>
<TabItem Style="{StaticResource TestStyle}">
</TabItem>
</TabControl>
</Grid>

WPF Changing the style of a UserControl in a ListView

I'm having issues setting the style of my UserContorl. I have the UserControl called BusyIndicator defined in a file. Below is the xaml.
<UserControl x:Class="Foo.Client.UI.SVGs.BusyIndicator"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<UserControl.Template>
<ControlTemplate>
<Border Width="{Binding Width}" Height="{Binding Height}" Visibility="{TemplateBinding Control.Visibility}">
<Canvas Width="{Binding Width}" Height="{Binding Height}" Visibility="{TemplateBinding Control.Visibility}">
<Path Fill="{Binding Foreground}"
Height="25"
Width="25"
Data="M20.519,4.617c-3.262-3.111-7.821-3.965-12.03-2.236 c-4.282,1.76-6.895,5.654-6.863,10.227l3.658-0.025C5.263,9.51,7.017,6.892,9.894,5.71c2.81-1.154,5.85-0.598,8.037,1.456 l-1.395,1.376h5.39V3.227L20.519,4.617z"/>
</Canvas>
</Border>
</ControlTemplate>
</UserControl.Template>
</UserControl>
I then reference the UserControl and use it in a ListView. The object the ListView is binding to has a property named Status. When Status is set to "Running", I'd like to change the style. When I run it, the Button is hidden so I know the Status property is notifying properly. But the svg:BusyIndicator control remains unchanged.
<UserControl x:Class="Foo.Views.Screens.CollectionResultsView"
AutomationProperties.AutomationId="CollectionResultsView"
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"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:svg="clr-namespace:Foo.Client.UI.SVGs;assembly=Foo.Client.UI"
d:DesignWidth="700">
<ListView ItemsSource="{Binding TargetStatusView}">
<StackPanel>
<Button>
<TextBlock Text="X"></TextBlock>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Running">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<svg:BusyIndicator Width="25" Height="25">
<svg:BusyIndicator.Style>
<Style TargetType="svg:BusyIndicator">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Running">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</svg:BusyIndicator>
</StackPanel>
</ListView>
</UserControl>
I also tried to change the TargetType to UserControl but that didn't work either.
<svg:BusyIndicator Width="25" Height="25">
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Running">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
</svg:BusyIndicator>
Setting <svg:BusyIndicator Width="25" Height="25" Visibility="Hidden"> does work but if I add <Setter Property="Visibility" Value="Hidden" /> to the style, above <Style.Triggers>, it does not work.
I also tried other properties like Opacity and Height without success.
What am I missing?
The issue was with the way we defined the BusyIndicator control. Because DataContext was set to {Binding RelativeSource={RelativeSource Self}}. With this, when it was used in the ListView, the context was the control itself and not the data bound to the ListView. So Binding="{Binding Status}" did work because the BusyIndicator usercontrol doesn't have a Status prooperty.
We updated the control below and it worked.
<UserControl x:Class="Foo.Client.UI.SVGs.BusyIndicator"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Canvas>
<Path Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Foreground}"
Data="M20.519,4.617c-3.262-3.111-7.821-3.965-12.03-2.236 c-4.282,1.76-6.895,5.654-6.863,10.227l3.658-0.025C5.263,9.51,7.017,6.892,9.894,5.71c2.81-1.154,5.85-0.598,8.037,1.456 l-1.395,1.376h5.39V3.227L20.519,4.617z">
</Path>
<Path Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Foreground}" Data="M4.733,20.634c3.26,3.111,7.82,3.964,12.03,2.234c4.281-1.76,6.894-5.652,6.862-10.227l-3.658,0.025c0.021,3.073-1.733,5.69-4.61,6.872c-2.808,1.155-5.85,0.598-8.037-1.457l1.396-1.375H3.324v5.315L4.733,20.634z" >
</Path>
</Canvas>
</UserControl>

Usercontrol style trigger not working

I am pretty sure this question has been asked from time to time since I found another question with about the same contents, here. But when I try to figure using all those pages, I'm just stuck...
This is what I'm trying to do. I created a usercontrol to select a file and show the path to the file in a textbox. Just like in HTML (input type=file). That all works great and as expected. But when I try to change the colour of the textbox using a trigger (FilePathIsValid), it just does not work. The dependency properties all work fine, as said above. But the style just is not assigned to the textbox.
Here is my XAML - can anybody tell me what I'm doing wrong? (Code Behind here, if needed)
<UserControl x:Class="Project.Controls.SelectFileBox"
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:Controls="clr-namespace:Project.Controls"
x:Name="ThisUserControl"
mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="300">
<UserControl.Resources>
<!-- This does not work... -->
<Style TargetType="{x:Type Controls:SelectFileBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="TextBoxBorderColor" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- Neither does this: FilePathIsValid can't be found -->
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="BorderBrush" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Margin="3" IsEnabled="{Binding ElementName=ThisUserControl,Path=TextBoxIsEnabled}" Text="{Binding ElementName=ThisUserControl,Path=FilePath}" BorderThickness="{Binding ElementName=ThisUserControl, Path=TextBoxBorderThickness}"/>
<Button Grid.Column="1" Margin="0,3,3,3" Content="{Binding ElementName=ThisUserControl, Path=ButtonText}" Click="SelectFileClick"/>
</Grid>
Ok, I understood the problem after looking at the codebehind.
All you need to do is add a binding to the BorderBrush property on the TextBox like below to get the right BorderBrush applied.
BorderBrush="{Binding ElementName=ThisUserControl, Path=TextBoxBorderColor}"
Full XAML for TextBox element:
<TextBox Grid.Column="0" Margin="3"
IsEnabled="{Binding ElementName=ThisUserControl,Path=TextBoxIsEnabled}"
Text="{Binding ElementName=ThisUserControl,Path=FilePath}"
BorderThickness="{Binding ElementName=ThisUserControl, Path=TextBoxBorderThickness}"
BorderBrush="{Binding ElementName=ThisUserControl, Path=TextBoxBorderColor}"/>
I have tried and tested, below is the screenshot
Alternative Way:
You could have a style for TextBox and have data triggers to change the borderbrush:
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ThisUserControl,
Path=FilePathIsValid}" Value="False">
<Setter Property="BorderBrush" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
With this approach, you don't need style for SelectFileBox and binding for BorderBrush property on TextBox.
If i understand correctly you want to set the textBoxbroder as red if the path is invalid then change your code as below
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="FilePathIsValid" Value="false">
<Setter Property="BorderBrush" Value="red"/>
</Trigger>
</Style.Triggers>
</Style>

On button hover, enable ResizeMode

I am trying to make window frame appear when user hovers "mybutton". This should work but for some reason it is not. What am I missing?
<Window x:Class="test2.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" WindowStyle="None" Loaded="ShellWindow_SourceInitialized" x:Name="mywindow">
<Window.Resources>
<Style TargetType="{x:Type Window}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=mybutton}" Value="True">
<Setter Property="ResizeMode" Value="CanResize" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=mybutton}" Value="False">
<Setter Property="ResizeMode" Value="NoResize" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Name="mygrid" Loaded="Grid_Loaded">
<Button Name="mybutton" Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"/>
</Grid>
(In case you are wondering what those "Loaded" functions are, they remove chrome while keeping the shadow and allowtransparency=false
http://marcin.floryan.pl/blog/2010/08/wpf-drop-shadow-with-windows-dwm-api)
At the end it will not be button but will react on whole window border (I can not find better way to enable resizing while removing all chrome)
In the style TargetType should be MainWindow
<Style TargetType="{x:Type local:MainWindow}">
where local has to be mapped to your namespace:
xmlns:local="clr-namespace:test2"
myButton is defined after style. XAML parser is not that smart. User the following XAML to get your intended behavior:
<Window x:Class="test2.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" WindowStyle="None" Loaded="ShellWindow_SourceInitialized" x:Name="mywindow">
<Grid Name="mygrid" Loaded="Grid_Loaded" >
<Button Name="mybutton" Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"/>
</Grid>
<Window.Style>
<Style TargetType="{x:Type Window}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=mybutton}" Value="True">
<Setter Property="ResizeMode" Value="CanResize" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=mybutton}" Value="False">
<Setter Property="ResizeMode" Value="NoResize" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Style>
</Window>

Data-Trigger Binding not working as expected

I have an style which defines a template for content controls.
For all controls that have the content property null, I'd like to show text saying the control is empty... but the xaml below is not working, does anybody know why?
<Style TargetType="ContentControl" x:Key="style">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Content, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
<Setter Property="ContentControl.Template">
<Setter.Value>
<ControlTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Background="Blue">EMPTY!</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<ContentControl Content="{x:Null}" Style="{StaticResource style}" />
It's not showing me the text 'EMPTY!'.
Your code works. Take that GUI designer of yours and throw it out the window.
The following works:
<Window x:Class="WpfApplication1.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>
<Style TargetType="ContentControl" x:Key="style">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Content, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
<Setter Property="ContentControl.Template">
<Setter.Value>
<ControlTemplate>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Background="Blue">EMPTY!</TextBlock>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ContentControl Content="{x:Null}" Style="{StaticResource style}" />
</Grid>
</Window>
simply change your textblock values from between context to property text="empty" like
<TextBlock Background="Blue" Text="Empty"></TextBlock>

Resources