How to Check Text Block Text value in Data Trigger in XAML - wpf

I want to check text value of text block if value is xyz. i don not want any operation but if text value is '#FF84312F' i want to set this text to foreground color of Text.
Below is my code.
How can i achieve this . Please Help me.
<TextBlock Text="#FF84312F">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, RelativeSource={RelativeSource Self}}" Value="*#">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

Try this:
<TextBlock Text="#FF84312F">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding Text,RelativeSource={RelativeSource Self}}" />
</Style>
</TextBlock.Style>
</TextBlock>
Or this:
<TextBlock Text="#FF84312F">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Text" Value="#FF84312F">
<Setter Property="Foreground" Value="{Binding Text,RelativeSource={RelativeSource Self}}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
It will set the Foreground to the value specified by the Text property, either unconditionally or conditionally (using a Trigger).

NOTE:
This answer is based on the comments of the answer provided by mm8
You can use a converter to convert your string to a SolidColorBrush:
Converter class:
public class TextToSolidColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var color = Brushes.Black;
try
{
var converted = new BrushConverter().ConvertFromString(value?.ToString());
color = converted != null ? (SolidColorBrush) converted : Brushes.Black;
}
catch (Exception e)
{
// ignored
}
return color;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
<Window.Resources>
<local:TextToSolidColorBrushConverter x:Key="TextToSolidColorBrushConverter"/>
</Window.Resources>
<TextBlock Text="Any text">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding Text,RelativeSource={RelativeSource Self}, Converter={StaticResource TextToSolidColorBrushConverter}}" />
</Style>
</TextBlock.Style>
</TextBlock>

based on your Comment:
What i want is . I have to check textblock text and if text block text
is color code then assign that color code to foreground. That's it
This will change the Color of your Textblock Foreground if Binded Text Value is a Color code else default color will shown.
<TextBlock Text="{Binding Text}" Foreground="{Binding Text, RelativeSource=
{RelativeSource Self}}"/>
or
<TextBlock Text="#0FFFFF" Foreground="{Binding Text, RelativeSource=
{RelativeSource Self}}"/>

Related

WPF converter for labels' content

I'm trying to override the output of a label, say it contained "Account" and a client wants account rendered as "Member" (so kind of think of this as a localisation converter?)
My Question; is this possible with "hardcoded" content? or MUST i create a static file containing all label content (with iNotifiyStatic of course)? *for binding?
xaml:
<Label Style="{StaticResource LabelLeft}" Content="Account Name:"></Label>
Resource File: Including all attempts made, from multiple sources heres the most meaningful one.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters ="clr-namespace:Company.Resources.Converters">
<converters:LocationLabelsConverter x:Key="LocationLabelsConverter" />
<Style x:Key="LabelLeft" TargetType="{x:Type Label}" >
<Setter Property="Margin" Value="10 0 0 0"></Setter>
<Setter Property="Height" Value="22"></Setter>
<Setter Property="Padding" Value="0 0 0 0"></Setter>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<!-- Att1 -->
<!--<Setter Property="TextBlock.Text" Value="{Binding RelativeSource={RelativeSource self},
Path=Content,
Converter={StaticResource LocationLabelsConverter}}"></Setter>-->
<!-- Att2 -->
<!--<Setter Property="Content">
<Setter.Value>
<Binding Path="Content" RelativeSource="{RelativeSource self}">
<Binding.Converter>
<converters:LocationLabelsConverter/>
</Binding.Converter>
</Binding>
</Setter.Value>
</Setter>-->
<!-- Att3 -->
<!--<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self},
Path=Content,
Converter={StaticResource LocationLabelsConverter}}">
<Setter Property="Content" Value="Test123"/>
</DataTrigger>
</Style.Triggers>-->
</Style>
And here's the converter:
[ValueConversion(typeof(string), typeof(string))]
public sealed class LocationLabelsConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value != null)
{
return "hello sweety";// (string)value; //The goal here in the end is to run it through a method to replace string with correct text.
}
else return null;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (string)value;
}
}
you can apply converter like this:
<Label Content="{Binding Source='Account Name:', Converter={StaticResource LocationLabelsConverter}"/>

Access Button's Tag property from ControlTemplate in XAML

In my Window I have a series of six buttons that indicate the six possible states for one of the properties of my ViewModel. The one that's active needs to be highlighted. To do this, I've created the following ControlTemplate for the buttons:
<ControlTemplate x:Key="SnijRichtingTemplate" TargetType="Button">
<Border Name="toggleButton" BorderThickness="1" BorderBrush="{StaticResource KleurRadioCheckOuter}" Background="Transparent" Width="20" Height="20" Cursor="Hand">
<TextBlock Name="text" Foreground="{StaticResource KleurRadioCheckOuter}"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"
ToolTip="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag.ToolTip}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource EqualityToBooleanConverter}">
<Binding Path="SnijRichting" />
<Binding Path="Tag" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter TargetName="toggleButton" Property="BorderBrush" Value="{StaticResource KleurTekstDonker}" />
<Setter TargetName="text" Property="Foreground" Value="{StaticResource KleurTekstDonker}" />
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="toggleButton" Property="BorderBrush" Value="{StaticResource Kleur2}" />
<Setter TargetName="text" Property="Foreground" Value="{StaticResource Kleur2}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
The template is then used like so:
<Button Grid.Column="0" Template="{StaticResource SnijRichtingTemplate}"
HorizontalAlignment="Right" Click="SnijRichting_Click"
Tag="{StaticResource XLinks}" />
Where the tag is just an instance defined in the XAML:
<wg:SnijRichting x:Key="XLinks" SnijAs="X" Negatief="True" />
The MultibindingConverter is nothing fancy:
public class EqualityToBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values[0] == values[1];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Basically, each button has a Tag with the new value. In the click handler, the ViewModel's property is set to the button's Tag. The button state is updated by checking whether the button's Tag is equal to the ViewModel property.
The problem is that this doesn't work. When the EqualityToBooleanConverter is executed, the second value is null. By removing the Path="Tag" bit from the second binding I see that the TemplatedParent is a ContentPresenter rather than the Button I was expecting, which explains why Tag is null. Now of course I could write a ValueConverter to get the correct value using VisualTreeHelper.GetParent to get the ContentPresenter's parent (which returns the desired Button), but surely there must be a way to do this from XAML? The obvious Path="Parent.Tag" doesn't work, since the Parent of the ContentPresenter is apparently a Border.
Does anyone know how to access the button's Tag property from XAML?
Found the problem. Turns out you need {RelativeSource Mode=Self}, not {RelativeSource TemplatedParent}.

AutoHide Progressbar with StyleTriggers

I would like to hide a progressbar in WPF using databinding. Whenever a property is 0, the progressbar should hide: I try the following code
(Info: My current datacontext is a class that holds an integer property 'CurrentIndex')
<ProgressBar Minimum="0" Maximum="100" Value="{Binding CurrentIndex, UpdateSourceTrigger=PropertyChanged}" Visibility="Visible">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentIndex}" Value="0">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
What is wrong with this code? Why does the progressbar still show up when the CurrentIndex is 0? (in the model behind, the value of 'CurrentIndex' is 0 by default, when the control is loaded)
DP precedence, do not set Visibility on the control itself (local value > style).
Other way to use visibility binding and a converter:
<Grid>
<Grid.Resources>
<App:VisibilityConverter x:Key="VisibilityConverter" />
</Grid.Resources>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding CurrentIndex, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding CurrentIndex, Mode=OneWay, Converter={StaticResource VisibilityConverter}}" />
</Grid>
The converter code (VisibilityConverter.cs):
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value == 0 ? Visibility.Hidden : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Your XAML was almost right!
Define your progressbar as you did:
<ProgressBar Minimum="0"
Maximum="100"
Value="{Binding CurrentIndex, UpdateSourceTrigger=PropertyChanged}"
Name="MyAutoHidingProgressBar" />
Don't forget to add the Name property AND do not set the Visibility here.
It will always override what is set in your Style.
Then define a Style as normal in your <Window.Resources>
<Window.Resources>
<Style TargetType="ProgressBar" x:Key="MyAutoHidingProgressBarStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyAutoHidingProgressBar, Path=Value}" Value="0">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
What this is basically doing is to check the Value of the progressbar itself, rather than your binding.
As a last step add the Style to your progressbar:
Style="{StaticResource MyAutoHidingProgressBarStyle}"
Now your ProgressBar will auto hide if its Value is 0.
You can also easily add a Trigger to hide it if its full.

WPF: How to hide the empty Hyperlink?

In the previous question of mine, I have asked how to hide an empty TextBlock, so that it doesn't take space in the panel. I have a new challenge now. How am I supposed to hide an empty Hyperlink:
<TextBlock>
<Hyperlink
NavigateUri="{Binding Path=Email}"
RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="{Binding Path=Email}" />
</Hyperlink>
</TextBlock>
This is what made the hiding possible in the previous question:
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
Providing this style on first TextBlock won't work because the Text property is not set. Providing style on Hyperlink doesn't hide the parent TextBlock and same happens if I try to hide the TextBlock inside the Hyperlink.
I am certain that my style needs to be applied on the Hyperlink, but the trigger inside should target the Visibility property of the 'Hyperlink's parentTextBlock`. What is the style supposed to look like?
Just use DataTrigger on the top level TextBlock to check whether the bound property is an empty string:
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Email}" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
EDIT:
Also you can try binding to the child hyperlink's NavigationUri property:
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Inlines
[0].NavigateUri}" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
The solution provided by Foovanadil that solves the similar issue by implementing visibility converter works the best in my opinion. It is the easiest to implement and can be reused whenever needed.
The converter should be implemented like this:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
if (string.IsNullOrEmpty(value as string))
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
And used like this:
<Window.Resources>
<!-- Visibility converter -->
<converters:VisibilityConverter x:Key="visibleConv" />
</Window.Resources>
...
<TextBlock Visibility="{Binding Something, Converter={StaticResource visibleConv}}">
<Hyperlink NavigateUri="{Binding Something}">
<TextBlock Text="{Binding Something}" />
</Hyperlink>
</TextBlock>
All credits go to the original solution provider: Foovanadil

WPF Datatrigger not firing when expected

I have the following XAML:
<TextBlock Text="{Binding ElementName=EditListBox, Path=SelectedItems.Count}" Margin="0,0,5,0"/>
<TextBlock Text="items selected">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=EditListBox, Path=SelectedItems.Count}" Value="1">
<Setter Property="TextBlock.Text" Value="item selected"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
The first text block happily changes with SelectedItems.Count, showing 0,1,2, etc. The datatrigger on the second block never seems to fire to change the text.
Any thoughts?
Alternatively, you could replace your XAML with this:
<TextBlock Margin="0,0,5,0" Text="{Binding ElementName=EditListBox, Path=SelectedItems.Count}"/>
<TextBlock>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="items selected"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=EditListBox, Path=SelectedItems.Count}" Value="1">
<Setter Property="Text" Value="item selected"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Converters can solve a lot of binding problems but having a lot of specialized converters gets very messy.
The DataTrigger is firing but the Text field for your second TextBlock is hard-coded as "items selected" so it won't be able to change. To see it firing, you can remove Text="items selected".
Your problem is a good candidate for using a ValueConverter instead of DataTrigger. Here's how to create and use the ValueConverter to get it to set the Text to what you want.
Create this ValueConverter:
public class CountToSelectedTextConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if ((int)value == 1)
return "item selected";
else
return "items selected";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Add the namespace reference to your the assembly the converter is located:
xmlns:local="clr-namespace:ValueConverterExample"
Add the converter to your resources:
<Window.Resources>
<local:CountToSelectedTextConverter x:Key="CountToSelectedTextConverter"/>
</Window.Resources>
Change your second textblock to:
<TextBlock Text="{Binding ElementName=EditListBox, Path=SelectedItems.Count, Converter={StaticResource CountToSelectedTextConverter}}"/>

Resources