Search code examples
wpfbindingstylesdatatrigger

WPF Style DataTrigger based on DependencyProperty binding


I'm working on a WPF form designer where you can drag and drop controls like Labels, TextBox, ComboBox to a design surface, then through a Property Grid user can set data bindings for each control. I have a requirement to show a red background for those controls that don't have a Binding set for a given property.

My original idea was to create a HasBindingConverter that would take the calling element itself and examine if it has a binding to a certain property. In this case TextBox.TextProperty

public class HasBindingConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        FrameworkElement fe = value as FrameworkElement;
        if(fe != null)
        {
            Binding binding = BindingOperations.GetBinding(fe, TextBox.TextProperty);
            return binding != null;
        }
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Then I added a Style associated to TextBox control type to the Resources section of my form which is a UserControl:

<UserControl.Resources>
    <Style TargetType="TextBox">
        <Style.Resources>
            <Converters:HasBindingConverter x:Key="HasBindingConv"/>
        </Style.Resources>
        <Style.Triggers>
            <DataTrigger
            Binding="{Binding,
            RelativeSource={RelativeSource Self},
            Converter={StaticResource HasBindingConv}}"
            Value="False">
                <Setter Property="TextBox.Background" Value="Red" />
                </DataTrigger>
 <DataTrigger Binding="{Binding 
            RelativeSource={RelativeSource Self},
            Converter={StaticResource HasBindingConv}}"
            Value="True">
                <Setter Property="TextBox.Background" Value="White" />
        </Style.Triggers>
    </Style>

So if TextBox does not have a Data Binding set for the TextBox.TextProperty then it will set its background to red. This part works fine, the problem is that when user sets the TextBox.TextProperty binding for this control my Converter is never invoked again so the background remains red.

Anyone knows how to invoke the trigger after setting the binding for this control? Or any other suggestions, I may be approaching the problem in a wrong way.

Thanks!


Solution

  • The reason why this happens, is the Binding won't be invoked again as the source i.e. the TextBox itself is never changed once it is created!

    Assume you are focused into a TextBox.

    1. So have the Tag property of the Container (Window / UserControl) set to the current control.

      myWindow.Tag = FocusManager.GetFocusedElement(myWindow);
      
    2. Change the trigger with this Binding.

      <DataTrigger
          Binding="{Binding,
          Path=Tag,
          RelativeSource={RelativeSource AncestorType=Window},
          Converter={StaticResource HasBindingConv}}" .. >
      
    3. Refresh Tag property of Window.

      myWindow.Tag = null;
      myWindow.Tag = FocusManager.GetFocusedElement(myWindow);