2012-01-19 11 views
16

Czy istnieje sposób na określenie przycinania tekstu na TextBlock, aby był z lewej strony?TekstTrimming od lewej

ja udaje się osiągnąć dwa z trzech scenariuszy (trzeci będąc jednym muszę):

  1. Regularne przycinanie

    <TextBlock 
        VerticalAlignment="Center" 
        Width="80" 
        TextTrimming="WordEllipsis" 
        Text="A very long text that requires trimming" /> 
    
    // Result: "A very long te..." 
    
  2. lewo przycinanie

    <TextBlock 
        VerticalAlignment="Center" 
        Width="80" 
        FlowDirection="RightToLeft" 
        TextTrimming="WordEllipsis" 
        Text="A very long text that requires trimming." /> 
    
    // Result: "...A very long te" 
    
  3. Po lewej przycinanie tam, gdzie widoczny jest koniec tekstu

    // Desired result: "...uires trimming" 
    

Czy ktoś wie, czy jest to możliwe? Dzięki.

+0

I co trzeba TextTrimming = "CharacterEllipsis" zamiast WordEllipsis. – Justin

Odpowiedz

3

Nie można zrobić out-of-the-box, ale mogę myśleć o dwie rzeczy, które mogą działać:

1) Załóż dołączony nieruchomość za TextBlock nazywa coś podobnego LeftTrimmingText. Następnie ustawisz tę właściwość zamiast właściwości Text. Na przykład.

<TextBlock my:TextBlockHelper.LeftTrimmingText="A very long text that requires trimming." /> 

Załączona właściwość obliczy, ile znaków może być faktycznie wyświetlanych, a następnie odpowiednio ustaw właściwość Tekst bloku tekstowego.

2) Utwórz własną klasę, która otoczy blokadę tekstu i dodaj własne właściwości, aby zająć się wymaganą logiką.

Myślę, że pierwsza opcja jest łatwiejsza.

+0

Niestety pierwsza opcja nie będzie łatwa. Silverlight nie udostępnia interfejsu API do renderowania tekstu/pomiaru. Najlepsze, co możesz zrobić, to wykryć * kiedy * pojawia się przycinanie. Zobacz ten post na blogu: http://www.scottlogic.co.uk/blog/colin/2011/01/showing-tooltips-on-trimmed-textblock-silverlight/ – ColinE

+2

ColinE: API pomiaru to sama funkcja TextBlock. Zasadniczo, tworzysz nową tymczasową blokadę TextBlock w kodzie i dodajesz kolejne znaki, aż ActualWidth stanie się większy, niż chcesz. Temp TextBlock nie musi być renderowany, ani nawet w drzewie graficznym. – RobSiklos

+0

@RobSiklow dobry punkt, to by działało. – ColinE

0

Nie wiem, czy to literówka, ale brakuje ci numeru full stop na końcu "pożądanego wyniku". Zakładam, że tego nie chcesz. Ponieważ wiesz, ile znaków powinno być wyświetlanych, możesz po prostu uzyskać podciąg całego łańcucha i wyświetlić go. Na przykład:

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; 

Jeśli nie wiesz, ile znaków chcesz uzyskać, możesz wykonać obliczenia w celu ich określenia. W twoim przykładzie, szerokość 80 daje znaki 17, możesz użyć tego współczynnika, jeśli zmieni się szerokość.

+5

Nie zapomnij - szerokość znaku zależy od czcionki – RobSiklos

+0

Tak, zakładam, że OP będzie znał czcionkę wcześniej. Jeśli nie, wówczas OP może użyć tej metody do określenia szerokości tekstu na podstawie czcionki: http://stackoverflow.com/questions/913053/how-do-you-determine-the-width-of-text-in- -a-wpf-treeviewitem-at-run-time – keyboardP

+1

"W twoim przykładzie, szerokość 80 daje 17 znaków, możesz użyć tego współczynnika, jeśli zmieni się szerokość." - Każda postać może mieć (i często ma) swoją indywidualną szerokość. Użycie współczynnika z jednego ciągu próbnego nie przyniesie żadnych dokładnych wyników. –

0

Będziesz musiał sam stworzyć ten efekt. @KeyboardP daje odpowiedź, jak zrobić przycinanie, jednak trudniejsze jest wiedzieć, ile trymować. Prawdopodobnie najlepszym rozwiązaniem jest skorzystanie z kodu znalezionego w sieci, który zapewnia przycinanie tekstu, zanim został dodany do struktury Silverlight. Na przykład:

http://nerdplusart.com/texttrimming-textblock-for-silverlight

To będzie trochę pracy, jednak dostosowanie go nie powinno być zbyt trudne,

3

Jeśli nie dbają o elips, ale po prostu chcą zobaczyć koniec tekstu zamiast początkowego, gdy zostanie odcięty, można zawinąć blok TextBlock w innym kontenerze i ustawić jego HorizontalAlignment w prawo. To odetnie go tak, jak chcesz, ale bez elipsy.

<Grid> 
    <TextBlock Text="Really long text to cutoff." HorizontalAlignment="Right"/> 
</Grid> 
2

Ten styl wykona zadanie. Sztuczka polega na ponownym zdefiniowaniu szablonu kontrolnego dla etykiety. Treść jest następnie umieszczana wewnątrz płótna obcinania i wyrównana z prawej strony płótna. Minimalna szerokość treści to szerokość płótna, więc tekst zawartości zostanie wyrównany do lewej, jeśli jest wystarczająco dużo miejsca i wyrównany do prawej po przycięciu.

Elipsy są włączane, jeśli szerokość zawartości jest większa niż płótno.

<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="...&#160;&#160;&#160;"> 
          <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> 

Istnieje kilka klas użytkowych tutaj

GteConverter

<c:GteConverter x:Key="GteConverter"/> 

który jest

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(); 
    } 
} 

i

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) { } 
} 

Tutaj to działa.

enter image description here enter image description here enter image description here

+0

Z jakiegoś powodu, etykieta OpacityMask nie działała właściwie dla mnie, ale udało mi się uzyskać pożądany efekt, używając zamiast tego właściwości Background - schludne rozwiązania, dzięki! – Wolfshead

+0

Wygląda jak najczystsze rozwiązanie. Kod nie zadziałał jednak dla mnie, nie pokazuje żadnego tekstu. –

Powiązane problemy