左侧的文本修剪
Posted
技术标签:
【中文标题】左侧的文本修剪【英文标题】:TextTrimming from left 【发布时间】:2012-02-14 04:44:23 【问题描述】:有没有办法将TextBlock
上的文本修剪指定为从左侧开始?
我已经成功完成了三个场景中的两个(第三种是我需要的):
定期修剪
<TextBlock
VerticalAlignment="Center"
Width="80"
TextTrimming="WordEllipsis"
Text="A very long text that requires trimming" />
// Result: "A very long te..."
左修剪
<TextBlock
VerticalAlignment="Center"
Width="80"
FlowDirection="RightToLeft"
TextTrimming="WordEllipsis"
Text="A very long text that requires trimming." />
// Result: "...A very long te"
在看到文本结尾的地方左修剪
// Desired result: "...uires trimming"
有人知道这是否可能吗?谢谢。
【问题讨论】:
我觉得你需要 TextTrimming="CharacterEllipsis" 而不是 WordEllipsis。 【参考方案1】:这种风格可以胜任。诀窍是重新定义标签的控制模板。然后将内容放在剪贴画布内并与画布右侧对齐。内容的最小宽度是画布的宽度,因此如果有足够的空间,内容文本将左对齐,剪辑时将右对齐。
如果内容的宽度大于画布,则会触发省略号。
<Style x:Key="LeftEllipsesLabelStyle"
TargetType="x:Type Label">
<Setter Property="Foreground"
Value="DynamicResource x:Static SystemColors.ControlTextBrushKey" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Padding"
Value="5" />
<Setter Property="HorizontalContentAlignment"
Value="Left" />
<Setter Property="VerticalContentAlignment"
Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="x:Type Label">
<Grid >
<Grid.Resources>
<LinearGradientBrush x:Key="HeaderBackgroundOpacityMask" StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="Black" Offset="0.5"/>
<GradientStop Color="Transparent" Offset="1"/>
</LinearGradientBrush>
</Grid.Resources>
<Canvas x:Name="Canvas"
ClipToBounds="True"
DockPanel.Dock="Top"
Height="Binding ElementName=Content, Path=ActualHeight">
<Border
BorderBrush="TemplateBinding BorderBrush"
Canvas.Right="0"
Canvas.ZIndex="0"
BorderThickness="TemplateBinding BorderThickness"
Background="TemplateBinding Background"
Padding="TemplateBinding Padding"
MinWidth="Binding ElementName=Canvas, Path=ActualWidth"
SnapsToDevicePixels="true"
x:Name="Content"
>
<ContentPresenter
HorizontalAlignment="TemplateBinding HorizontalContentAlignment"
Content="Binding RelativeSource=RelativeSource AncestorType=Label, Path=Content"
RecognizesAccessKey="True"
SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels"
VerticalAlignment="TemplateBinding VerticalContentAlignment"
>
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="Binding FontSize, RelativeSource=RelativeSource AncestorType=x:Type Label"/>
<Setter Property="FontWeight" Value="Binding FontWeight, RelativeSource=RelativeSource AncestorType=x:Type Label"/>
<Setter Property="FontStyle" Value="Binding FontStyle, RelativeSource=RelativeSource AncestorType=x:Type Label"/>
<Setter Property="FontFamily" Value="Binding FontFamily, RelativeSource=RelativeSource AncestorType=x:Type Label"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
<Label
x:Name="Ellipses"
Canvas.Left="0"
Canvas.ZIndex="10"
FontWeight="TemplateBinding FontWeight"
FontSize="TemplateBinding FontSize"
FontFamily="TemplateBinding FontFamily"
FontStyle="TemplateBinding FontStyle"
VerticalContentAlignment="Center"
OpacityMask="StaticResource HeaderBackgroundOpacityMask"
Background="TemplateBinding Background"
Foreground="RoyalBlue"
Height="Binding ElementName=Content, Path=ActualHeight"
Content="...   ">
<Label.Resources>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Value="true">
<DataTrigger.Binding>
<MultiBinding Converter="StaticResource GteConverter">
<Binding ElementName="Canvas" Path="ActualWidth"/>
<Binding ElementName="Content" Path="ActualWidth"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Resources>
</Label>
</Canvas>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="DynamicResource x:Static SystemColors.GrayTextBrushKey" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这里有几个实用程序类
GteConverter
<c:GteConverter x:Key="GteConverter"/>
这是
public class RelationalValueConverter : IMultiValueConverter
public enum RelationsEnum
Gt,Lt,Gte,Lte,Eq,Neq
public RelationsEnum Relations get; protected set;
public RelationalValueConverter(RelationsEnum relations)
Relations = relations;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
if(values.Length!=2)
throw new ArgumentException(@"Must have two parameters", "values");
var v0 = values[0] as IComparable;
var v1 = values[1] as IComparable;
if(v0==null || v1==null)
throw new ArgumentException(@"Must arguments must be IComparible", "values");
var r = v0.CompareTo(v1);
switch (Relations)
case RelationsEnum.Gt:
return r > 0;
break;
case RelationsEnum.Lt:
return r < 0;
break;
case RelationsEnum.Gte:
return r >= 0;
break;
case RelationsEnum.Lte:
return r <= 0;
break;
case RelationsEnum.Eq:
return r == 0;
break;
case RelationsEnum.Neq:
return r != 0;
break;
default:
throw new ArgumentOutOfRangeException();
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
throw new NotImplementedException();
和
public class GtConverter : RelationalValueConverter
public GtConverter() : base(RelationsEnum.Gt)
public class GteConverter : RelationalValueConverter
public GteConverter() : base(RelationsEnum.Gte)
public class LtConverter : RelationalValueConverter
public LtConverter() : base(RelationsEnum.Lt)
public class LteConverter : RelationalValueConverter
public LteConverter() : base(RelationsEnum.Lte)
public class EqConverter : RelationalValueConverter
public EqConverter() : base(RelationsEnum.Eq)
public class NeqConverter : RelationalValueConverter
public NeqConverter() : base(RelationsEnum.Neq)
它正在工作。
【讨论】:
由于某种原因,Label 的 OpacityMask 无法正常工作,但我设法通过使用 Background 属性获得了我想要的效果 - 巧妙的解决方案,谢谢! 看起来是最干净的解决方案。该代码对我不起作用,它根本不显示任何文本。 你有一个如何使用它的例子吗?我是 WPF 和 XAML 的新手。我收到关于未定义命名空间前缀“c”且未找到类型“c:GteConverter”的错误。我假设我没有正确的位置/文件中的所有内容,或者我遗漏了一些东西。 嗨,克里斯。我已经有一年多没有使用 XAML 了,对我来说它又开始像黑魔法了。但是,上面的代码假设您知道如何处理 XAML 命名空间。如果不是可能阅读docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/… 可能会有所帮助。如果不以尽可能完整的信息开始另一个问题,那么最新的人可能会提供帮助。 嗯,谢谢你的原帖。我想我明白了。 Visual Studio 显示的错误在实际编译代码时可能会消失,这让我大吃一惊。【参考方案2】:如果您不关心省略号,而只是想在文本被截断时看到文本的结尾而不是开头,则可以将 TextBlock 包装在另一个容器中,并将其 HorizontalAlignment 设置为 Right。这将按照您的意愿将其切断,但没有省略号。
<Grid>
<TextBlock Text="Really long text to cutoff." HorizontalAlignment="Right"/>
</Grid>
【讨论】:
【参考方案3】:我不知道这是否是一个错字,但您在“期望的结果”末尾缺少full stop
。我假设你不想要它。由于您知道应该显示多少个字符,您可以只获取整个字符串的子字符串并显示它。例如,
string origText = "A very long text that requires trimming.";
//15 because the first three characters are replaced
const int MAXCHARACTERS = 15;
//MAXCHARACTERS - 1 because you don't want the full stop
string sub = origText.SubString(origText.Length-MAXCHARACTERS, MAXCHARACTERS-1);
string finalString = "..." + sub;
textBlock.Text = finalString;
如果您不知道您需要多少个字符,那么您可以执行计算来确定它。在您的示例中,80
的宽度导致 17
字符,如果宽度发生变化,您可以使用该比率。
【讨论】:
别忘了 - 字符宽度取决于字体 是的,我假设 OP 会事先知道字体。如果不是,那么 OP 可以使用这种方法根据字体确定文本宽度:***.com/questions/913053/… "在您的示例中,宽度为 80 会产生 17 个字符,如果宽度发生变化,您可以使用该比率。" - 每个字符可以有(并且经常有)它自己的宽度。使用一个样本字符串中的比率不会产生任何精确的结果。【参考方案4】:你不能开箱即用地做到这一点,但我可以想到两件事可能会奏效:
1) 为 TextBlock 创建一个名为 LeftTrimmingText 的附加属性。然后,您将设置此属性而不是 Text 属性。例如
<TextBlock my:TextBlockHelper.LeftTrimmingText="A very long text that requires trimming." />
附加属性会计算实际可以显示多少个字符,然后相应地设置 TextBlock 的 Text 属性。
2) 创建您自己的包装 TextBlock 的类,并添加您自己的属性来处理所需的逻辑。
我认为第一个选项更容易。
【讨论】:
不幸的是,第一个选项并不容易。 Silverlight 不公开文本呈现/测量 API。您能做的最好的事情是检测 何时 发生修剪。请参阅此博文:scottlogic.co.uk/blog/colin/2011/01/… ColinE:测量 API 是 TextBlock 本身。基本上,您在代码中创建一个新的临时 TextBlock,并不断添加字符,直到 ActualWidth 变得比您想要的大。临时 TextBlock 不需要渲染,甚至不需要在可视化树中。 谢谢@RobSiklos 和 ColinE以上是关于左侧的文本修剪的主要内容,如果未能解决你的问题,请参考以下文章