Show Tooltip when text is being trimmed

前端 未结 6 1246
北海茫月
北海茫月 2020-12-30 02:45
  
     
        

        
6条回答
  •  感情败类
    2020-12-30 03:24

    Working off of Eyjafj...whatever's idea, I arrived at a working, mostly declarative solution that at least doesn't require a custom control. The first hurdle to overcome is getting at the TextBlock. Because the ToolTip is rendered outside of the visual tree, you can't use a RelativeSource binding or ElementName to get at the TextBlock. Luckily, the ToolTip class provides a reference to its related element via the PlacementTarget property. So you can bind the ToolTip's Visibility property to the ToolTip itself and use its PlacementTarget property to access properties of the TextBlock:

    
    

    The next step is using a converter to look at the TextBlock we've bound to to determine if the ToolTip should be visible or not. You can do this using the ActualWidth and the DesiredSize. ActualWidth is exactly what it sounds like; the width your TextBlock has been rendered to on the screen. DesiredSize is the width your TextBlock would prefer to be. The only problem is, DesiredSize seems to take the TextTrimming into account and does not give you the width of the full, untrimmed text. To solve this, we can re-call the Measure method passing Double.Positive infinity to, in effect, ask how wide the TextBlock would be if it its width were not constrained. This updates the DesiredSize property and then we can do the comparison:

    textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
    
    if (((FrameworkElement)value).ActualWidth < ((FrameworkElement)value).DesiredSize.Width)
        return Visibility.Visible;
    

    This approach is actually illustrated here as an attached behavior if you want to apply it automatically to TextBlocks or don't want to waste resources on creating ToolTips that will always be invisible. Here is the full code for my example:

    The Converter:

    public class TrimmedTextBlockVisibilityConverter : IValueConverter
    {
    
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null) return Visibility.Collapsed;
    
            FrameworkElement textBlock = (FrameworkElement)value;
    
            textBlock.Measure(new System.Windows.Size(Double.PositiveInfinity, Double.PositiveInfinity));
    
            if (((FrameworkElement)value).ActualWidth < ((FrameworkElement)value).DesiredSize.Width)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The XAML:

    
        
    
    
    ....
    
    
        
            
                
                    
                
            
        
    
    

提交回复
热议问题