asusralis
Topic Author
Posts: 109
Joined: 30 Jul 2018, 05:03

Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

19 Feb 2021, 00:11

Sometimes, when I try to show a popup I get the specified error above. I am creating a custom system of tooltips that are interactable.

I have an attachable property that listens to a MouseOver event. Once this happens, it calls a static method to create a popup and displays it. I add it to my top-level root Grid and it seems to work for the most part, but sometimes when I attach the property to an element that itself will be in a popup I get the error message.

I removed a lot of code. If the issue isn't obvious I can include more. I don't think this is a Noesis bug... I just don't understand what I'm doing wrong.
        public static readonly DependencyProperty ToolTipContentProperty = DependencyProperty.RegisterAttached(
            "ToolTipContent",
            typeof(UIElement),
            typeof(TTEx),
            new PropertyMetadata(OnValueChanged));
            
        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ...
            element.MouseEnter += (s, e) => TooltipManager.Show(d as FrameworkElement);
        }
        public static async void Show(FrameworkElement element)
        {
            var popup = new Popup();
            
            ...

#if NOESIS
            Navigation.Current.RootParent.ContentRoot.Children.Add(popup);
#endif
            popup.IsOpen = true;
        }
Video as well: https://files.catbox.moe/ijwks6.mp4

This error has also happened when I tried to add my attached property to a Run. I fixed that by passing the entire TextBlock instead of the run into Show(). Thank you for any insight you can give!
 
User avatar
sfernandez
Site Admin
Posts: 2056
Joined: 22 Dec 2011, 19:20

Re: Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

19 Feb 2021, 12:56

I was investigating the issue and found that popup is not checking if the target element is in the tree, so it was producing those error messages. Could you please report it in our bugtracker so we fix it for the next release.

Anyway, the source of the problem is that you are hiding the unit info popup when hovering over the 'Hitpoints' text because in your IsRoot function you are considering only the Parent to traverse up the logical tree, but the element could be part of a template, so it could have a TemplatedParent but not a logical parent. You can do something like this:
private static bool IsRoot(FrameworkElement element)
{
    var current = element;
    while (current != null)
    {
        if (current is Popup) return false;
        current = current.Parent != null ? current.Parent : current.TemplatedParent;
    }
    return true;
}
 
asusralis
Topic Author
Posts: 109
Joined: 30 Jul 2018, 05:03

Re: Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

20 Feb 2021, 14:55

Oh, thank you so much! I was so confused for a second with you knowing that existed in the project. I will have to read up on the difference between parent and templated parent, I didn't know that could be a problem.
 
asusralis
Topic Author
Posts: 109
Joined: 30 Jul 2018, 05:03

Re: Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

20 Feb 2021, 18:14

Sorry to ask another thing, but do you know why this wouldn't work when I try to pass a Run through ShowAsync? I get the same "Visual 'Run' is not a descendant of the specified ancestor 'RootVisual'. It works when I pass the TextBlock, but I need to show the tooltip right next to the specific Run.

(RichTextBlock.cs)
        private static void HandleLoc(MarkupString s, string key, string loc, InlineCollection inlines, RichTextBlock block)
        {
            var run = new Run(loc);
            run.Foreground = new SolidColorBrush(Color.FromRgb(254, 198, 25));

            run.MouseEnter += async (sender, e) =>
            {
                var text = new RichTextBlock();
                text.TextWrapping = TextWrapping.Wrap;
                text.FormattedText = Localizer.Get($"Tooltip.{key}");

                await StackableToolTipManager.ShowAsync(run, title: key, customContent: text);
            };

            run.MouseLeave += async (sender, e) =>
            {
                await StackableToolTipManager.HideAsync();
            };

            inlines.Add(run);
        }
        
Edit: it seems to happen with controls inside ItemsControls as well when the tooltip is defined through XAML.
 
User avatar
sfernandez
Site Admin
Posts: 2056
Joined: 22 Dec 2011, 19:20

Re: Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

23 Feb 2021, 01:26

This happens because Runs are not part of the visual tree, they just provide the information to build the text for the TextBlock.
But you can use an InlineUIContainer with a TextBlock so you have a visual element to target in your tooltip:
<TextBlock TextWrapping="Wrap">
  <Run Text="Some text"/>
  <InlineUIContainer>
    <TextBlock Text="hint" ToolTip="This is a tooltip" Margin="0,0,0,-4" ToolTipService.Placement="Top" ToolTipService.VerticalOffset="-5"/>
  </InlineUIContainer>
  <Run Text="more text"/>
</TextBlock>
You'll need to adjust the margin of the internal TextBlock to match the text baseline. That vertical alignment should be automatic when InlineUIContainer contains text as it occurs in WPF, but that is not yet implemented in Noesis, so adding that margin is the only workaround for now.
Edit: it seems to happen with controls inside ItemsControls as well when the tooltip is defined through XAML.
How are you defining the tooltip when used inside an ItemsControl?
 
asusralis
Topic Author
Posts: 109
Joined: 30 Jul 2018, 05:03

Re: Visual 'TextBlock' Is not a descendant of the specified ancestor 'RootVisual'

23 Feb 2021, 09:28

Oh I see, thanks for the information. I am doing it here:
<ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,5,0,0">
                        <local:TTEx.ToolTipContent>
                            <StackPanel>
                                <TextBlock
                                    FontSize="{StaticResource FontSize.Large}"
                                    FontWeight="Bold"
                                    Foreground="{StaticResource LiveTextColor}"
                                    Text="{Binding Name.Value}" />
                                <local:RichTextBlock
                                    Margin="0,0,0,0"
                                    FormattedText="{Binding Description.Value}"
                                    TextWrapping="Wrap" />
                            </StackPanel>
                        </local:TTEx.ToolTipContent>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock
                                FontSize="{StaticResource FontSize.Large}"
                                FontWeight="Bold"
                                Foreground="{StaticResource LiveTextColor}"
                                Text="{Binding Name.Value}" />
                            <TextBlock
                                Margin="10,0,0,0"
                                VerticalAlignment="Bottom"
                                Foreground="LightGray"
                                Text="{Binding SkillType.Value}" />
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

Who is online

Users browsing this forum: No registered users and 2 guests