0

Let's say I have the following class:

public class MyClass : System.Windows.FrameworkElement
{
    public static readonly DependencyProperty HasFocusProperty = DependencyProperty.RegisterAttached("HasFocus", typeof(bool), typeof(MyClass), new PropertyMetadata(default(bool)));

    public bool HasFocus
    {
        get => (bool)GetValue(HasFocusProperty);
        set => SetValue(HasFocusProperty, value);
    }

    public System.Windows.Controls.TextBox TextBox { get; set; }
}

I want to change some UI properties of TextBox via XAML Template Trigger based on the property HasFocus, so I do the following:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:win="clr-namespace:System.Windows.Controls">
    <Style TargetType="{x:Type win:TextBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type win:TextBox}">
                    <ControlTemplate.Triggers>
                        <Trigger Property="MyClass.HasFocus" Value="True">
                            <Setter TargetName="Border" Property="BorderBrush" Value="Red" />
                            <Setter TargetName="Border" Property="BorderThickness" Value="2" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 </ResourceDictionary>

However, the style is not applied when setting HasFocus = true.

Within the properties of TextBox, I can see that the trigger is registered. If I change <Trigger Property="MyClass.HasFocus" Value="True"> to <Trigger Property="MyClass.HasFocus" Value="False">, my style is applied initially. So I think my XAML definition is okay.

Any ideas how to solve this?

mu88
  • 4,156
  • 1
  • 23
  • 47
  • You are creating a template for a built-in `TextBox` and try to bind to a property of `MyClass`. This doesn't make sense. How is a `TextBox` supposed to know there to look for the `HasFocus` property of `MyClass`? Maybe you want an [attached property](https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/attached-properties-overview). Or what's the purpose of `MyClass`? – mm8 Apr 01 '19 at 08:21
  • I'm new to WPF, so please excuse my question: why does it not make sense? I want `TextBox` to react on a property change of another class. For this, do I have to use an Attached Property instead of a Dependency Property? Does a Dependency Property only support changes within the same class? – mu88 Apr 01 '19 at 08:34
  • 1
    Yes, a template that targets type A cannot bind to a property of another type B unless there is an instance of this type to bind to somwhere. – mm8 Apr 01 '19 at 08:35
  • Thank you for your explanation! Could I bind to the `TextEditor` instance of `MyClass`? – mu88 Apr 01 '19 at 08:37
  • Sorry for the typo, I mean the `TextBox` instance of `MyClass` – mu88 Apr 01 '19 at 08:39
  • Why would you want to bind to the `TextBox` when your property is defined in `MyClass`? – mm8 Apr 01 '19 at 08:47
  • I'm just curious whether this would be an alternative of using an Attached Property – mu88 Apr 01 '19 at 08:51
  • If you define a template for `MyClass`, you could bind to any of its properties in this template. – mm8 Apr 01 '19 at 08:51

1 Answers1

2

An element in a template that is applied to a TextBox cannot bind to a property of a MyClass, unless there is a MyClass element to bind to somewhere in the visual tree.

If you want to be able to set a custom HasFocus property of a TextBox, you should create an attached property:

public class FocusExtensions
{
    public static readonly DependencyProperty SetHasFocusProperty = DependencyProperty.RegisterAttached(
        "HasFocus",
        typeof(bool),
        typeof(FocusExtensions),
        new FrameworkPropertyMetadata(false)
    );

    public static void SetHasFocus(TextBox element, bool value)
    {
        element.SetValue(SetHasFocusProperty, value);
    }

    public static bool GetHasFocus(TextBox element)
    {
        return (bool)element.GetValue(SetHasFocusProperty);
    }
}

It can be set for any TextBox element:

<TextBox local:FocusExtensions.HasFocus="True">
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="local:FocusExtensions.HasFocus" Value="True">
                    <Setter Property="BorderBrush" Value="Red" />
                    <Setter Property="BorderThickness" Value="2" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
mm8
  • 163,881
  • 10
  • 57
  • 88