This started with weird behaviour that I thought was tied to my implementation of ToString()
, and I asked this question: Why won't WPF databindings show text when ToString() has a collaborating object?
It turns out to have nothing to do with collaborators and is reproducible.
When I bind Label.Content
to a property of the DataContext
that is declared as an interface type, ToString()
is called on the runtime object and the label displays the result.
When I bind TextBlock.Text
to the same property, ToString()
is never called and nothing is displayed. But, if I change the declared property to a concrete implementation of the interface, it works as expected.
Is this somehow by design? If so, any idea why?
To reproduce:
public interface IFoo { string foo_part1 { get; set; } string foo_part2 { get; set; } } public class Foo : IFoo { public string foo_part1 { get; set; } public string foo_part2 { get; set; } public override string ToString() { return foo_part1 + " - " + foo_part2; } }
public class Bar
{
public IFoo foo
{
get { return new Foo {foo_part1 = "first", foo_part2 = "second"}; }
}
}
Set the XAML of Window1 to:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Label Content="{Binding foo, Mode=Default}"/>
<TextBlock Text="{Binding foo, Mode=Default}"/>
</StackPanel>
</Window>
in Window1.xaml.cs:
public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new Bar(); } }
When you run this application, you'll see the text only once (at the top, in the label). If you change the type of foo
property on Bar
class to Foo
(instead of IFoo
) and run the application again, you'll see the text in both controls.
Data binding is a mechanism in WPF applications that provides a simple and easy way for Windows Runtime apps to display and interact with data. In this mechanism, the management of data is entirely separated from the way data. Data binding allows the flow of data between UI elements and data object on user interface.
Data binding is a mechanism in XAML applications that provides a simple and easy way for Windows Runtime Apps using partial classes to display and interact with data. The management of data is entirely separated from the way the data is displayed in this mechanism.
Binding path syntax. Use the Path property to specify the source value you want to bind to: In the simplest case, the Path property value is the name of the property of the source object to use for the binding, such as Path=PropertyName . Subproperties of a property can be specified by a similar syntax as in C#.
The DataContext property is the default source of your bindings, unless you specifically declare another source, like we did in the previous chapter with the ElementName property. It's defined on the FrameworkElement class, which most UI controls, including the WPF Window, inherits from.
I know this thread is old but I found a workaround for this problem. Use the StringFormat property on the binding:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Label Content="{Binding foo, Mode=Default}"/>
<TextBlock Text="{Binding foo, Mode=Default, StringFormat={}{0}}"/>
</StackPanel>
</Window>
Yes you are right. Obviously the ContentControl.Content
property is implemented differently from the TextBlock.Text
property. One obvious difference of course is that the ContentControl
will actually generate a TextBlock
instance for a content object that is not a Visual
and doesn't have a DataTemplate
. The TextBlock
does not. It will render the text by itself. In both cases the string is determined by
IValueConverter
(if present in the binding)TypeConverter
(if declared)object.ToString()
It seems that this algorithm differs only in step 3 between TextBlock
and ContentControl
as you have shown. While the ContentControl
actually resolves the object behind the interface, the TextBlock
does not. Interesting.
I guess this is something that you have to live with. You have several options now:
ContentControl
instead of a TextBlock
IValueConverter
and use it in the bindingTypeConverter
for your interfaceIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With