Short version:
WPF seems to always set a local value when using an IValueConverter in a binding, even if that converter returns Binding.DoNothing.
My question is: What do I have to return or do to tell WPF to use the inherited value?
Please note: I don’t want to use DataTriggers as this would bloat up my code significantly because I would need one data trigger along with a converter for every color my current converter returns.
Long version with reproduction:
Imagine the following scenario:
I have a Button in which a TextBlock is located. There exists a style for the Button that sets the Foreground property. This value is inherited by the TextBlock.
Now I want to create a value converter that converts the value of the TextBlock to a Brush to be used as the Foreground – but only in some cases. In the cases in which I don’t want to set a special color, I return Binding.DoNothing. My understanding was that this would make the TextBlock to continue to use the inherited value.
Unfortunatelly, my understanding was not correct. Even when returning Binding.DoNothing a local value is set. This has been verified with Snoop.
The problem can be easily reproduced with this simple example:
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:WpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<WpfApplication1:DummyConverter x:Key="DummyConverter" />
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Red" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground"
Value="{Binding Path=Text, RelativeSource={RelativeSource Self}, Converter={StaticResource DummyConverter}}" />
</Style>
</Window.Resources>
<StackPanel>
<Button><TextBlock>Text1</TextBlock></Button>
<Button><TextBlock>Text2</TextBlock></Button>
</StackPanel>
</Window>
Converter:
public class DummyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.ToString() == "Text2")
return Brushes.Cyan;
return Binding.DoNothing;
}
}
As you can see, the first button has a black text instead of red. If you remove the style for TextBlock both buttons will have the correct red text.
Question:
What do I have to do to prevent this? Is there some value to return that tells the engine to continue using the inherited value?
To answer your question: according to this thread, no. As soon as you give the TextBlock a style setter (#4), any value returned will override inherited properties (#7).
Instead, you could create a MultiBinding like so: