tabina
tabina

Reputation: 1155

Access the value of an Attached property in a binding

I am using attached properties to limit the input into a textbox. Now I would like to display the min and max limit in a tooltip but the tooltip either displays '0' for the two values or 'DependencyProperty.UnsetValue'. What's wrong with my bindings?

<TextBox Text="{Binding Value}"
            Helper:InputService.InputMode="Numeric"
            Helper:InputService.Min="7"
            Helper:InputService.Max="{Binding Limit}">
            <TextBox.ToolTip>
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding Converter="{converters:StringsToStringMultiConverter}" ConverterParameter=":" StringFormat="{}({0})">
                        <Binding Path="(Helper:InputService.Min)" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}"/>  
                        <Binding Path="(Helper:InputService.Max)" RelativeSource="{RelativeSource Self}"/> 
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </TextBox.ToolTip>
        </TextBox>

(The Converter just appends the two values like (min:max)). For the Binding with {RelativeSource Self} I always get '0'. Searching for the parent element results in the 'UnsetValue'.

I also would like to put the tooltip part into a text box style and use a trigger to check if the inputmode is numeric.

Parts of the InputService:

/// <summary>
/// The attached property for the input mode.
/// </summary>
public static readonly DependencyProperty InputModeProperty = DependencyProperty.RegisterAttached(
  "InputMode",
  typeof (InputMode),
  typeof (InputService),
  new UIPropertyMetadata(InputMode.All, OnInputModeChanged));

/// <summary>
/// The attached property for checking the min limit of a number. Only applied if input mode is Numeric.
/// </summary>
public static readonly DependencyProperty MinProperty = DependencyProperty.RegisterAttached(
  "Min",
  typeof (int),
  typeof (InputService));

/// <summary>
/// The attached property for checking the max limit of a number. Only applied if input mode is Numeric.
/// </summary>
public static readonly DependencyProperty MaxProperty = DependencyProperty.RegisterAttached(
  "Max",
  typeof (int),
  typeof (InputService));


private static void OnInputModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var mode = (InputMode) e.NewValue;

  if (d is TextBox)
  {
    var textBox = (TextBox) d;
    var textPastedEventHandler = new RoutedEventHandler(OnTextPasted);
    textBox.AddHandler(CommandManager.PreviewExecutedEvent, textPastedEventHandler, true);

    if (mode == InputMode.Numeric)
    {
      textBox.PreviewTextInput += AllowNumbersOnly;
    }
    else
    {
      textBox.PreviewTextInput -= AllowNumbersOnly;
    }        
  }
}

The min and max values are used in the AllowNumberOnly which composes the value from the input digits and checks if it exceeds one of the limits.

EDIT:

I simplified the code and removed the converter to be sure it's not the converter or the multibinding.

<TextBox Text="{Binding Value}"
            Helper:InputService.InputMode="Numeric"
            Helper:InputService.Min="7"
            Helper:InputService.Max="{Binding Limit}">
            <TextBox.ToolTip>
                <TextBlock>
                    <TextBlock.Text>
                        <Binding Path="(Helper:InputService.Min)" RelativeSource="{RelativeSource Self}" StringFormat="{}({0})"/>                             
                    </TextBlock.Text>
                </TextBlock>
            </TextBox.ToolTip>
        </TextBox>

In the InputService I added default values to the min and max properties like this:

   public static readonly DependencyProperty MinProperty = DependencyProperty.RegisterAttached(
  "Min",
  typeof(int),
  typeof(InputService),
  new PropertyMetadata()
     {
       DefaultValue = 0
     });

   public static readonly DependencyProperty MaxProperty = DependencyProperty.RegisterAttached(
  "Max",
  typeof(int),
  typeof(InputService),
  new PropertyMetadata()
    {
      DefaultValue = int.MaxValue
    });

But still the tooltip shows '(0)'.

EDIT:

Ok, this one works:

<TextBox Text="{Binding Value}"
            Helper:InputService.InputMode="Numeric"
            Helper:InputService.Min="7"
            Helper:InputService.Max="{Binding Limit}">
       <TextBox.ToolTip>
          <MultiBinding Converter="{converters:StringsToStringMultiConverter}" ConverterParameter=":">
             <Binding Path="(Helper:InputService.Min)" RelativeSource="{x:Static RelativeSource.Self}"/>
             <Binding Path="(Helper:InputService.Max)" RelativeSource="{x:Static RelativeSource.Self}"/>
           </MultiBinding>
       </TextBox.ToolTip>
  </TextBox>

I removed the TextBlock around the MultiBinding and the binding to relativesource self seems to work. What does not work anymore is the StringFormat. If defined in the MultiBinding, it will be ignored. If I define it as ContentStringFormat in a surrounding ToolTip, the bindings do not work anymore. Any suggestions?

Upvotes: 0

Views: 2374

Answers (1)

Sheridan
Sheridan

Reputation: 69959

Your Binding syntax in your first line looks perfect, so I'm guessing that you have another problem. I have successfully used the following Path syntax:

<Binding Path="(Namespace:ClassName.PropertyName)" RelativeSource="{RelativeSource 
    AncestorType=ControlClassName}"/>  

But that is equivalent to your example:

<Binding Path="(Namespace:ClassName.PropertyName)" RelativeSource="{RelativeSource 
    Mode=FindAncestor, AncestorType={x:Type ControlClassName}}"/> 

I can also confirm that the declaration of your Attached Properties are perfectly fine... no problems there either. However, I'm wondering what would happen if you set default values for your Min and Max properties... maybe you're getting an DependencyProperty.UnsetValue because that property... has no value?

Upvotes: 1

Related Questions