wpf - Text Trimming desde la izquierda
silverlight xaml (4)
Este estilo hará el trabajo. El truco es redefinir una plantilla de control para la etiqueta. El contenido se coloca dentro de un lienzo de recorte y se alinea a la derecha del lienzo. El ancho mínimo del contenido es el ancho del lienzo, por lo que el texto del contenido se alineará a la izquierda si hay suficiente espacio y se alinea a la derecha cuando se recorta.
Los puntos suspensivos se activan si el ancho del contenido es mayor que el lienzo.
<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>
Hay un par de clases de utilidad aquí
GteConverter
<c:GteConverter x:Key="GteConverter"/>
cual es
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();
}
}
y
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) { }
}
Aquí está funcionando.
¿Hay una manera de especificar el recorte de texto en un TextBlock
para que sea del lado izquierdo?
Me las arreglé para lograr dos de los tres escenarios (el tercero es el que necesito):
Recorte regular
<TextBlock VerticalAlignment="Center" Width="80" TextTrimming="WordEllipsis" Text="A very long text that requires trimming" /> // Result: "A very long te..."
Recorte izquierdo
<TextBlock VerticalAlignment="Center" Width="80" FlowDirection="RightToLeft" TextTrimming="WordEllipsis" Text="A very long text that requires trimming." /> // Result: "...A very long te"
Recorte a la izquierda donde se ve el final del texto.
// Desired result: "...uires trimming"
¿Alguien sabe si esto es posible? Gracias.
No puede hacer esto fuera de la caja, pero puedo pensar en dos cosas que podrían funcionar:
1) Crear una propiedad adjunta para TextBlock llamada algo como LeftTrimmingText. A continuación, establecería esta propiedad en lugar de la propiedad Texto. P.ej
<TextBlock my:TextBlockHelper.LeftTrimmingText="A very long text that requires trimming." />
La propiedad adjunta calcularía cuántos caracteres podrían realmente visualizarse y, a continuación, establecería la propiedad de texto del TextBlock en consecuencia.
2) Cree su propia clase que contenga un TextBlock, y agregue sus propias propiedades para cuidar la lógica requerida.
Creo que la primera opción es más fácil.
No sé si es un error tipográfico, pero te estás perdiendo el full stop
final al final de tu "resultado deseado". Asumiré que no lo quieres. Como sabe cuántos caracteres se deben mostrar, puede obtener una subcadena de toda la cadena y mostrarla. Por ejemplo,
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;
Si no sabe cuántos caracteres desea por adelantado, puede realizar un cálculo para determinarlo. En su ejemplo, un ancho de 80
resultados en 17
caracteres, puede usar esa proporción si el ancho cambia.
Si no le importan los puntos suspensivos, pero solo desea ver el final del texto en lugar del principio cuando se corta, puede ajustar el TextBlock dentro de otro contenedor y establecer su alineación horizontal a la derecha. Esto lo cortará como quieras, pero sin la elipse.
<Grid>
<TextBlock Text="Really long text to cutoff." HorizontalAlignment="Right"/>
</Grid>