TextTrimming слева
Есть ли способ указать обрезку текста на 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"
Кто-нибудь знает, возможно ли это? Благодарю.
Ответы
Ответ 1
Вы не можете делать это из коробки, но я могу думать о двух вещах, которые могут сработать:
1) Создайте вложенное свойство TextBlock, которое называется нечто вроде LeftTrimmingText. Затем вы должны установить это свойство вместо свойства Text. Например.
<TextBlock my:TextBlockHelper.LeftTrimmingText="A very long text that requires trimming." />
Вложенное свойство подсчитывает, сколько символов действительно может отображаться, а затем соответствующим образом задайте свойство Text для TextBlock.
2) Создайте свой собственный класс, который обертывает TextBlock, и добавьте ваши собственные свойства, чтобы позаботиться о требуемой логике.
Я думаю, что первый вариант проще.
Ответ 2
Если вам не нужны эллипсы, но просто хотите увидеть конец текста вместо начала, когда он отключится, вы можете обернуть TextBlock внутри другого контейнера и установить его HorizontalAlignment вправо. Это отключит его так, как вы хотите, но без elipse.
<Grid>
<TextBlock Text="Really long text to cutoff." HorizontalAlignment="Right"/>
</Grid>
Ответ 3
Этот стиль выполнит эту работу. Трюк состоит в том, чтобы переопределить шаблон управления для метки. Затем содержимое помещается внутри холста для обрезки и выравнивается справа от холста. Минимальная ширина содержимого - это ширина холста, поэтому текст содержимого будет выровнен по левому краю, если при обрезании будет достаточно места и выровнено по правому краю.
Эллипсы включаются, если ширина содержимого больше холста.
<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) { }
}
Вот он работает.
![enter image description here]()
![enter image description here]()
![enter image description here]()
Ответ 4
Я не знаю, является ли это опечаткой, но вам не хватает 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
, вы можете использовать это соотношение при изменении ширины.
Ответ 5
Вам нужно будет создать этот эффект самостоятельно. @KeyboardP дает ответ о том, как сделать обрезку, однако более сложная часть - это то, насколько важно обрезать. Вероятно, лучшим решением является взятие некоторого кода, найденного в Интернете, который обеспечивал обрезку текста, прежде чем он был добавлен в среду Silverlight. Например:
http://nerdplusart.com/texttrimming-textblock-for-silverlight
Это будет небольшая работа, однако ее адаптация не должна быть слишком сложной,