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>