wpfbindingdatacontext

Datacontext conflicts


<UserControl x:Class="WatermarkTextBox"
             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"
             mc:Ignorable="d"
             d:DesignHeight="30"
             d:DesignWidth="250">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>
    <Border>
        <Grid x:Name="grid">
            <TextBlock Text="{Binding Watermark, FallbackValue=This prompt dissappears as you type...}"
                       Visibility="{Binding ElementName=txtUserEntry, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
            <TextBox Name="txtUserEntry"
                     Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
        </Grid>
    </Border>
</UserControl>

The above code shows my WatermarkTextBox control. In the code behind file I have set the DataContext. I left out all the code for the DP's of the control.

public WatermarkTextBox()
{
    InitializeComponent();
    grid.DataContext = this;
}

I had to bind the DataContext to the grid because otherwise the Text properties of both the watermark and actual text wouldn't display. The problem now is that I can't set the Background of the Border outside of the Grid.

I tried the code below but then only the Background of the Border is set and not the watermark and actual text.

public WatermarkTextBox()
{
    InitializeComponent();
    this.DataContext = this;
    grid.DataContext = this;
}

Solution

  • In a UserControl like this you should never exlicitly set the DataContext to this or anyting else, because the DataContext is usually set externally when you use the UserControl somewhere in your application. The externally applied DataContext is typically (part of) the application's view model.

    You should instead change your internal bindings so that they use an explicit RelativeSource:

    <TextBlock
        Text="{Binding Path=Watermark,
                       RelativeSource={RelativeSource AncestorType=UserControl},
                       FallbackValue=This prompt dissappears as you type...}"
        Visibility="{Binding ElementName=txtUserEntry,
                             Path=Text.IsEmpty,
                             Converter={StaticResource BooleanToVisibilityConverter}}" />
    <TextBox
        Name="txtUserEntry"
        Text="{Binding Path=Text,
                       UpdateSourceTrigger=PropertyChanged,
                       RelativeSource={RelativeSource AncestorType=UserControl}}" />
    

    and then remove any DataContext assignment from the UserControl's constructor.

    See e.g. this answer (and many other similar) that discuss this topic in detail.