Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 如何确定是否正在修剪文本块文本?_Wpf_Textblock - Fatal编程技术网

Wpf 如何确定是否正在修剪文本块文本?

Wpf 如何确定是否正在修剪文本块文本?,wpf,textblock,Wpf,Textblock,以下文本块按预期进行包装和修剪。修剪文本时,将显示省略号“…” <TextBlock MaxWidth="60" MaxHeight="60" Text="This is some long text which I would like to wrap." TextWrapping="Wrap" TextTrimming="CharacterEllipsis" /> 我想在全文的文本上显示一个工具提示,但仅当文本被修剪时。我不确

以下文本块按预期进行包装和修剪。修剪文本时,将显示省略号“…”

<TextBlock 
    MaxWidth="60" 
    MaxHeight="60" 
    Text="This is some long text which I would like to wrap."
    TextWrapping="Wrap" 
    TextTrimming="CharacterEllipsis" />

我想在全文的文本上显示一个工具提示,但仅当文本被修剪时。我不确定如何可靠地确定是否正在显示“…”


如何确定文本是否被修剪?

我最近没有做过很多WPF,所以我不确定这是否是您想要的,但请查看这篇文章:。这有点复杂,但它似乎解决了你正在问的同一个问题。更新:该网站似乎消失了,但你可以在网站上找到这篇文章。查看斯科特·张伯伦的答案和示例代码(谢谢斯科特)。

因为亚历克答案中的链接已关闭,我从回程机器中找到了一个。您无法下载文章中链接的代码,因此这里是代码的预组装版本。我在尝试使其工作时遇到了一两个问题,因此此代码与本文示例中的代码略有不同

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TextBlockService
{
    //Based on the project from http://web.archive.org/web/20130316081653/http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/
    public static class TextBlockService
    {
        static TextBlockService()
        {
            // Register for the SizeChanged event on all TextBlocks, even if the event was handled.
            EventManager.RegisterClassHandler(
                typeof(TextBlock),
                FrameworkElement.SizeChangedEvent,
                new SizeChangedEventHandler(OnTextBlockSizeChanged),
                true);
        }


        private static readonly DependencyPropertyKey IsTextTrimmedKey = DependencyProperty.RegisterAttachedReadOnly("IsTextTrimmed", 
            typeof(bool), 
            typeof(TextBlockService), 
            new PropertyMetadata(false));

        public static readonly DependencyProperty IsTextTrimmedProperty = IsTextTrimmedKey.DependencyProperty;

        [AttachedPropertyBrowsableForType(typeof(TextBlock))]
        public static Boolean GetIsTextTrimmed(TextBlock target)
        {
            return (Boolean)target.GetValue(IsTextTrimmedProperty);
        }


        public static readonly DependencyProperty AutomaticToolTipEnabledProperty = DependencyProperty.RegisterAttached(
            "AutomaticToolTipEnabled",
            typeof(bool),
            typeof(TextBlockService),
            new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));

        [AttachedPropertyBrowsableForType(typeof(DependencyObject))]
        public static Boolean GetAutomaticToolTipEnabled(DependencyObject element)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            return (bool)element.GetValue(AutomaticToolTipEnabledProperty);
        }

        public static void SetAutomaticToolTipEnabled(DependencyObject element, bool value)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(AutomaticToolTipEnabledProperty, value);
        }

        private static void OnTextBlockSizeChanged(object sender, SizeChangedEventArgs e)
        {
            TriggerTextRecalculation(sender);
        }

        private static void TriggerTextRecalculation(object sender)
        {
            var textBlock = sender as TextBlock;
            if (null == textBlock)
            {
                return;
            }

            if (TextTrimming.None == textBlock.TextTrimming)
            {
                textBlock.SetValue(IsTextTrimmedKey, false);
            }
            else
            {
                //If this function is called before databinding has finished the tooltip will never show.
                //This invoke defers the calculation of the text trimming till after all current pending databinding
                //has completed.
                var isTextTrimmed = textBlock.Dispatcher.Invoke(() => CalculateIsTextTrimmed(textBlock), DispatcherPriority.DataBind);
                textBlock.SetValue(IsTextTrimmedKey, isTextTrimmed);
            }
        }

        private static bool CalculateIsTextTrimmed(TextBlock textBlock)
        {
            if (!textBlock.IsArrangeValid)
            {
                return GetIsTextTrimmed(textBlock);
            }

            Typeface typeface = new Typeface(
                textBlock.FontFamily,
                textBlock.FontStyle,
                textBlock.FontWeight,
                textBlock.FontStretch);

            // FormattedText is used to measure the whole width of the text held up by TextBlock container
            FormattedText formattedText = new FormattedText(
                textBlock.Text,
                System.Threading.Thread.CurrentThread.CurrentCulture,
                textBlock.FlowDirection,
                typeface,
                textBlock.FontSize,
                textBlock.Foreground);

            formattedText.MaxTextWidth = textBlock.ActualWidth;

            // When the maximum text width of the FormattedText instance is set to the actual
            // width of the textBlock, if the textBlock is being trimmed to fit then the formatted
            // text will report a larger height than the textBlock. Should work whether the
            // textBlock is single or multi-line.
            // The "formattedText.MinWidth > formattedText.MaxTextWidth" check detects if any 
            // single line is too long to fit within the text area, this can only happen if there is a 
            // long span of text with no spaces.
            return (formattedText.Height > textBlock.ActualHeight || formattedText.MinWidth > formattedText.MaxTextWidth);
        }

    }
}

如果TextBlock是ListBoxItem数据模板的一部分,则上述解决方案对我无效。 我提出另一个解决办法:

public class MyTextBlock : System.Windows.Controls.TextBlock
{

    protected override void OnToolTipOpening(WinControls.ToolTipEventArgs e)
    {
        if (TextTrimming != TextTrimming.None)
        {
            e.Handled = !IsTextTrimmed(); 
        }
    }

    private bool IsTextTrimmed()
    {
        Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
        return ActualWidth < DesiredSize.Width;
    }
}
公共类MyTextBlock:System.Windows.Controls.TextBlock
{
受保护的超控无效开启(WinControl.ToolTipEventArgs e)
{
if(textciming!=textciming.None)
{
e、 Handled=!IsTextTrimmed();
}
}
私有bool IsTextTrimmed()
{
度量(新大小(双正不确定度,双正不确定度));
返回实际宽度
XAML:


扩展bidy的答案。这将创建一个文本块,仅在未显示所有文本时显示工具提示。工具提示将根据内容调整大小(与默认工具提示相反,默认工具提示将保留一行框,文本将被截断)

使用系统;
使用System.Windows;
使用System.Windows.Controls;
名称空间MyComponents
{
公共类CustomTextBlock:TextBlock
{
已初始化受保护的覆盖无效(事件参数e)
{
//我们需要一个可根据内容调整大小的工具提示——一个带有TextWrapping.Wrap的textblock可以做到这一点
var toolTipTextBlock=new TextBlock();
toolTipTextBlock.TextWrapping=TextWrapping.Wrap;
//将工具提示文本绑定到当前文本块文本绑定
var binding=GetBindingExpression(TextProperty);
if(绑定!=null)
{
SetBinding(TextProperty,binding.ParentBinding);
}
var toolTipPanel=new StackPanel();
toolTipPanel.Children.Add(toolTipTextBlock);
工具提示=工具提示面板;
基础。初始化(e);
}
OLTIPOINTOPEN上的受保护覆盖无效(ToolTipEventArgs e)
{
if(textciming!=textciming.None)
{
e、 Handled=!IsTextTrimmed();
}
}
私有bool IsTextTrimmed()
{
度量(新大小(双正不确定度,双正不确定度));
返回实际宽度
XAML用法:

    <Window ...
        xmlns:components="clr-namespace:MyComponents"
     ... >
    
    <components:CustomTextBlock Text="{Binding Details}" TextTrimming="CharacterEllipsis" />

我在使用Alex answer时遇到了一个小问题,必须稍微更改我的逻辑,以澄清文本块中的文本是否被修剪

var formattedText = new FormattedText(
            Text, System.Threading.Thread.CurrentThread.CurrentCulture, FlowDirection, typeface, FontSize,
            Foreground, VisualTreeHelper.GetDpi( this ).PixelsPerDip ) { MaxTextWidth = ActualWidth };
        //Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

 return ( Math.Floor(formattedText.Height ) > ActualHeight || Math.Floor( formattedText.MinWidth ) > ActualWidth;
这对我来说非常合适

我定义了一个用户控件,它是启用省略号的TextBlock。然后我为OnMouseUp和OnMouseDown定义了两个函数,这样当用户单击溢出的textblock时,就会显示一个带有完整值的工具提示

这是OnMouseDown函数

private void TextBlockWithToolTipView_OnMouseDown(
        object sender,
        MouseButtonEventArgs e )
    {
        var typeface = new Typeface(
            FontFamily,
            FontStyle,
            FontWeight,
            FontStretch);

        var formattedText = new FormattedText(
            Text, System.Threading.Thread.CurrentThread.CurrentCulture, FlowDirection, typeface, FontSize,
            Foreground, VisualTreeHelper.GetDpi( this ).PixelsPerDip ) { MaxTextWidth = ActualWidth };

        if (Math.Floor(formattedText.Height) > ActualHeight || Math.Floor(formattedText.MinWidth) > ActualWidth )
        {
            if( ToolTip is ToolTip tt )

            {
                {
                    if( tt.PlacementTarget == null )
                    {
                        tt.PlacementTarget = this;
                    }

                    tt.IsOpen = true;
                    e.Handled = true;
                }
            }
        }
    }
这就是Xaml位

<TextBlock 
         ToolTipService.IsEnabled="True"
         MouseDown="TextBlockWithToolTipView_OnMouseDown"
         MouseLeave="TextBlockWithToolTipView_OnMouseLeave"   
         TextTrimming="CharacterEllipsis"
         TextWrapping="WrapWithOverflow">
<TextBlock.ToolTip>
        <ToolTip 
            DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
        <TextBlock Text="{Binding Path=Text, Mode=OneWay }"
                       TextWrapping="Wrap"/>
        </ToolTip>
    </TextBlock.ToolTip>
</TextBlock>


上述文章中提到的算法正是我想要的-谢谢@l33t我还需要Wayback机器缓存的链接。这个答案实际上需要说明如何解决问题,而不是仅仅删除链接。同意@sydan。不要简单地链接。S.O.的不良行为。当你这样做的时候,你会在我们现在的同一个地方结束。。。一个标记的答案,实际上没有。档案现在也关闭了。看另一个有副本的答案。完美陈述的问题-很好的一个。:)像这样使用回程机的ups很好。我一直忘了它就在那里。它已经是“选择加入”了,因为你必须用
自动启用它。(为了响应代码注释
而不是强制*all*TextBlocks采用TextBlockService样式,使用x:Key允许更友好的选择加入模式。
)@KellyElton我不想在窗口中的每个TextBlock上放置不必要的触发器。如果您发现它不会造成任何开销,您可以将其应用于每个文本框。这个应用程序是为一个数据输入应用程序编写的,它有一个带有可编辑单元格的表格,总共有几百个文本框。这是一个很好的干净解决方案。然而,它对我不起作用:我的文本块正在被修剪(我看到省略号),但我的DesiredSize.Width等于实际宽度。
var formattedText = new FormattedText(
            Text, System.Threading.Thread.CurrentThread.CurrentCulture, FlowDirection, typeface, FontSize,
            Foreground, VisualTreeHelper.GetDpi( this ).PixelsPerDip ) { MaxTextWidth = ActualWidth };
        //Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

 return ( Math.Floor(formattedText.Height ) > ActualHeight || Math.Floor( formattedText.MinWidth ) > ActualWidth;
private void TextBlockWithToolTipView_OnMouseDown(
        object sender,
        MouseButtonEventArgs e )
    {
        var typeface = new Typeface(
            FontFamily,
            FontStyle,
            FontWeight,
            FontStretch);

        var formattedText = new FormattedText(
            Text, System.Threading.Thread.CurrentThread.CurrentCulture, FlowDirection, typeface, FontSize,
            Foreground, VisualTreeHelper.GetDpi( this ).PixelsPerDip ) { MaxTextWidth = ActualWidth };

        if (Math.Floor(formattedText.Height) > ActualHeight || Math.Floor(formattedText.MinWidth) > ActualWidth )
        {
            if( ToolTip is ToolTip tt )

            {
                {
                    if( tt.PlacementTarget == null )
                    {
                        tt.PlacementTarget = this;
                    }

                    tt.IsOpen = true;
                    e.Handled = true;
                }
            }
        }
    }
<TextBlock 
         ToolTipService.IsEnabled="True"
         MouseDown="TextBlockWithToolTipView_OnMouseDown"
         MouseLeave="TextBlockWithToolTipView_OnMouseLeave"   
         TextTrimming="CharacterEllipsis"
         TextWrapping="WrapWithOverflow">
<TextBlock.ToolTip>
        <ToolTip 
            DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
        <TextBlock Text="{Binding Path=Text, Mode=OneWay }"
                       TextWrapping="Wrap"/>
        </ToolTip>
    </TextBlock.ToolTip>
</TextBlock>