Search code examples
c#wpfxamlbindingmarkup-extensions

MarkupExtension identify FrameworkElement when TargetObject is Binding


I have an interesting MarkupExtension use case serving an IValueConverter, which accepts an int (Counter), and maps that to an L10N formatted localization. I am not certain how to best approach solving it, whether it is even solvable for that matter.

<TextBlock Text="{Binding Path=Counter, Converter={wpf:GettextFormatConverter Binding string format support: {0:n0}}}" HorizontalAlignment="Center" />

In and of itself, the mapping is formatting correctly, but I want to gain awareness of the XAML content area in the following way.

I can add a simple MarkupExtension property DomainName, which I will probably do anyway, but it just feels awkward, i.e.

<TextBlock Text="{Binding Path=Counter, Converter={wpf:GettextFormatConverter Binding string format support: {0:n0}}, DomainName=Example}" HorizontalAlignment="Center" />

I would like to discern DomainName from a parent L10N content wrapper, i.e.

<LocalizationContent DomainName="Example">
    <TextBlock Text="{Binding Path=Counter, Converter={wpf:GettextFormatConverter Binding string format support: {0:n0}}}" HorizontalAlignment="Center" />
</LocalizationContent>

Which I can easily do when the extension is directly mapped into the control text or content.

<LocalizationContent DomainName=Example>
    <TextBlock Text="{wpf:Gettext Varying case example:}" HorizontalAlignment="Center" />
</LocalizationContent>

In this case, TargetObject and corresponding TargetProperty are DependencyObject and DependencyProperty, respectively. Which lends itself to discovering the FrameworkElement parent.

But not in the primary target use case. The problem is, the TargetObject in this use case is a Binding, and not the parent TextBlock FrameworkElement. The rub is this: how best to identify that TextBlock (FrameworkElement) from the ProvideValue context? Without necessarily having to jump into XAML service providers, things of this nature.

Edit: Fair point, providing a bit of clarification. I am not talking about the values being bound, per se. I want access to the TextBlock (FrameworkElement). I don't care about the Binding (or MultiBinding) itself. However, TargetObject being exposed is not DependencyObject, but rather Binding (or MultiBinding).

So the rub of my question is simply, is there a way?

// Implementing the MarkupExtension, in service to a (Multi)Binding converter
public override object ProvideValue(IServiceProvider serviceProvider)
{
    // Convenience GetService extension method
    var valueProvider = serviceProvider.GetService<IProvideValueTarget>();

    // TODO: never happens, since TargetObject was a (Multi)Binding
    if (valueProvider.TargetObject is DependencyObject dependencyObject)
    {
        // TODO: do something interesting with the DO
    }

    return Gettext(Localizer);
}

Make sense? Can it be clearer what I need to know there?


Solution

  • So, humoring Andy's and Joe's response, doing the naive thing and swapping in a multi binding, the net net there is, instead of Binding for TargetOject, now it is MultiBinding, which prima facie, is more or less what I might have expected. And it is. I do not understand how I can gain visibility of the host TextBlock FrameworkElement, for which the DependencyProperty (DependencyObject) binding is taking place.

    <TextBlock HorizontalAlignment="Center">
        <TextBlock.Text>
            <MultiBinding Converter="{wpf:GettextMultiFormatConverter Binding string format support: {0:n0}}">
                <Binding Path="Counter" Mode="OneWay" />
            </MultiBinding>
        </TextBlock.Text>
    </TextBlock>