2
votes

I'm trying to do a Binding on a Property of my Textblockextension. I'm doing that in a CellTemplate but it always gives me that one Error which says:

Binding is not possible for the Property "SetInteractiveText" of type "TextBlock". Binding can only be done with a DependencyProperty of a DependencyObject

Extension:

public static class TextBlockExtension
{
    private static readonly Regex UrlRegex = new Regex(@"(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(500));


    private static readonly Regex EmailRegex = new Regex(@"(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(500));

    private static readonly Regex PhoneRegex = new Regex(@"\+?[\d\-\(\)\. ]{5,}", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));

    private const string RelativeUriDefaultPrefix = "http://";


    public static readonly DependencyProperty InteractiveTextProperty = DependencyProperty.RegisterAttached("InteractiveText", typeof(string), typeof(TextBlock), new UIPropertyMetadata(null,OnInteractiveTextChanged));

    private static void OnInteractiveTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBlock = d as TextBlock;
        if (textBlock == null) return;

        // we remove all the inlines
        textBlock.Inlines.Clear();

        // if we have no data, we do not need to go further
        var rawText = e.NewValue as string;
        if (string.IsNullOrEmpty(rawText)) return;


        var lastPosition = 0;
        var matches = new Match[3];
        do
        {
            matches[0] = UrlRegex.Match(rawText, lastPosition);
            matches[1] = EmailRegex.Match(rawText, lastPosition);
            matches[2] = PhoneRegex.Match(rawText, lastPosition);

            var firstMatch = matches.Where(x => x.Success).OrderBy(x => x.Index).FirstOrDefault();
            if (firstMatch == matches[0])
            {
                // the first match is an URL
                CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index);
                lastPosition = CreateUrlElement(textBlock, firstMatch);
            }
            else if (firstMatch == matches[1])
            {
                // the first match is an email
                CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index);
            }
            else if (firstMatch == matches[2])
            {
                // the first match is a phonenumber
                CreateRunElement(textBlock, rawText, lastPosition, firstMatch.Index);
            }
            else
            {
                // no match, we add the whole text
                textBlock.Inlines.Add(new Run { Text = rawText.Substring(lastPosition) });
                lastPosition = rawText.Length;
            }
        }
        while (lastPosition < rawText.Length);
    }

    private static void CreateRunElement(TextBlock textBlock, string rawText, int startPosition, int endPosition)
    {
        var fragment = rawText.Substring(startPosition, endPosition - startPosition);
        textBlock.Inlines.Add(new Run { Text = fragment });
    }

    private static int CreateUrlElement(TextBlock textBlock, Match urlMatch)
    {
        Uri targetUri;
        if (Uri.TryCreate(urlMatch.Value, UriKind.RelativeOrAbsolute, out targetUri))
        {
            var link = new Hyperlink();
            link.Inlines.Add(new Run { Text = urlMatch.Value });

            if (targetUri.IsAbsoluteUri)
                link.NavigateUri = targetUri;
            else
                link.NavigateUri = new Uri(RelativeUriDefaultPrefix + targetUri.OriginalString);


            textBlock.Inlines.Add(link);
        }
        else
        {
            textBlock.Inlines.Add(new Run { Text = urlMatch.Value });
        }

        return urlMatch.Index + urlMatch.Length;
    }

    public static string GetInteractiveText(DependencyObject obj)
    {
        return (string)obj.GetValue(InteractiveTextProperty);
    }

    public static void SetInteractiveText(DependencyObject obj, string value)
    {
        obj.SetValue(InteractiveTextProperty, value);
    }
}

And XAML:

 <dxg:TreeListColumn Header="Beschreibung" FieldName="Message" >
      <dxg:TreeListColumn.CellTemplate>
           <DataTemplate>
                <TextBlock  utilities:TextBlockExtension.InteractiveText="{Binding Path=(dxg:RowData.Row)}"/>
           </DataTemplate>
      </dxg:TreeListColumn.CellTemplate>
 </dxg:TreeListColumn>

Hope someone can help me!

1
It says Binding is not possible for the Property "SetInteractiveText" of type "TextBlock". Binding can only be done with a DependencyProperty of a DependencyObjectSokui
Change destionation target type of you AttachedProperty to TextBlockExtension. First: Right now it type of TextBlock but TextBlock doesn't have such property!! change this ->typeof(TextBlock) to typeof(TextBlockExtension).Shakra
@Shakra Thanks! That fixed it!Sokui
@Shakra Maybe you can write this as an answer so i can close the thread and give you rep?Sokui

1 Answers

2
votes

The owner type of the attached property (i.e. the third argument to RegisterAttached) must be the class in which the property is declared, not any possible type where the property is applied.

Here it must be TextBlockExtension, not TextBlock:

public static readonly DependencyProperty InteractiveTextProperty =
    DependencyProperty.RegisterAttached(
        "InteractiveText",
        typeof(string),
        typeof(TextBlockExtension), // here
        new PropertyMetadata(null, OnInteractiveTextChanged));