3
votes

I would like to add tooltips in Xamarin for UWP by using a native view and the Windows.UI.Xaml Nuget package. I have added the following reference to the xaml page to get the windows native view:

<ContentPage 

             xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"   

</ContentPage>

I can successfully access native windows controls, e.g. a TextBlock:

<    win: TextBlock Text="S"/>

However, when I try to add the tooltip to the control:

<win:TextBlock Text="S" ToolTipService.ToolTip="Service agreement"/>

I get the following exception during compilation:

"Xamarin.Forms.Xaml.XamlParseException: 'Position 56:45. Type ToolTipService not found in xmlns http://xamarin.com/schemas/2014/forms'"

Is the system getting confused between the standard Windows.UI.Xaml.Controls namespace and the extended one from the Nuget package?

1
I search some info, but I can not find any way to add ToolTips for native view in Forms, if you want to achieve this , I suggest you can custom render for any control that you want to display ToolTips, this is one same thread that you can take a look:stackoverflow.com/questions/41978916/…Cherry Bu - MSFT
@CherryBu-MSFT: Thank you. Do you recommend that I customize an entry, as explained here: docs.microsoft.com/en-gb/xamarin/xamarin-forms/app-fundamentals/…? Or is there a TextBox-specific renderer in UWP that I should use?ccdmfc

1 Answers

5
votes

ToolTipService is attached property, and it will not find ToolTipService assembly in Forms client, the better way is use Effect to create your own tip service and render it in UWP platform. You could refer the following steps.

  • Create a subclass of the PlatformEffect class.

  • Override the OnAttached method and write logic to customize the control.

  • Override the OnDetached method and write logic to clean up the control customization, if required.

  • Add a ResolutionGroupName attribute to the effect class. This attribute sets a company wide namespace for effects, preventing collisions with other effects with the same name. Note that this attribute can only be applied once per project.

  • Add an ExportEffect attribute to the effect class. This attribute registers the effect with a unique ID that's used by Xamarin.Forms, along with the group name, to locate the effect prior to applying it to a control. The attribute takes two parameters – the type name of the effect, and a unique string that will be used to locate the effect prior to applying it to a control.

UWP Code Part

[assembly: ResolutionGroupName("Microsoft")]
[assembly: ExportEffect(typeof(UWPToolTipEffect), nameof(TooltipEffect))]

namespace NativeSwitch.UWP
{
    public class UWPToolTipEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            var control = Control ?? Container;

            if (control is DependencyObject)
            {
                ToolTip toolTip = new ToolTip();
                toolTip.Content = TooltipEffect.GetText(Element);
                switch (TooltipEffect.GetPosition(Element))
                {
                    case TooltipPosition.Bottom:
                        toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Bottom;
                        break;
                    case TooltipPosition.Top:
                        toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Top;
                        break;
                    case TooltipPosition.Left:
                        toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Left;
                        break;
                    case TooltipPosition.Right:
                        toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Right;
                        break;
                    default:
                        return;
                }
                ToolTipService.SetToolTip(control, toolTip);
            }

        }

        protected override void OnDetached()
        {

        }
    }
}

Forms code part

public static class TooltipEffect
{

    public static readonly BindableProperty TextProperty =
      BindableProperty.CreateAttached("Text", typeof(string), typeof(TooltipEffect), string.Empty, propertyChanged: OnTextChanged);

    public static readonly BindableProperty PositionProperty =
      BindableProperty.CreateAttached("Position", typeof(TooltipPosition), typeof(TooltipEffect), TooltipPosition.Bottom);


    public static string GetText(BindableObject view)
    {
        return (string)view.GetValue(TextProperty);
    }

    public static void SetText(BindableObject view, string value)
    {
        view.SetValue(TextProperty, value);
    }

    public static TooltipPosition GetPosition(BindableObject view)
    {
        return (TooltipPosition)view.GetValue(PositionProperty);
    }

    public static void SetPosition(BindableObject view, TooltipPosition value)
    {
        view.SetValue(PositionProperty, value);
    }

    static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var view = bindable as View;
        if (view == null)
        {
            return;
        }

        string text = (string)newValue;
        if (!string.IsNullOrEmpty(text))
        {
            view.Effects.Add(new ControlTooltipEffect());
        }
        else
        {
            var toRemove = view.Effects.FirstOrDefault(e => e is ControlTooltipEffect);
            if (toRemove != null)
            {
                view.Effects.Remove(toRemove);
            }
        }
    }

}

public enum TooltipPosition
{
    Bottom,

    Right,

    Left,

    Top
}

class ControlTooltipEffect : RoutingEffect
{
    public ControlTooltipEffect() : base($"Microsoft.{nameof(TooltipEffect)}")
    {

    }
}

Usage

// forms project namesapce
xmlns:effects="clr-namespace:ToolTipTestApp"
......

<win:TextBlock
    effects:TooltipEffect.Position="Right"
    effects:TooltipEffect.Text="Hello"
    Text="Hello Wrold"
    />