1

I'm trying to set CharacterEllipsis on text inside a DataTemplate of an ItemsControl.

<Window x:Class="CustomPanel.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomPanel;assembly="
Title="Window1" Height="400" Width="400">
<Window.Resources>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="TextTrimming" Value="CharacterEllipsis"></Setter>
    </Style>

    <DataTemplate DataType="{x:Type local:Person}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Name}"
                       Margin="100,0,0,0"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <ItemsControl ItemsSource="{Binding Persons}" 
                  Grid.Column="0">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

</Grid>

I've also tried setting width to the ItemsControl, StackPanel's and the TextBlock itself.

Any Ideas?

EDIT

To inhance that this is not an issue of the Style or the StackPanel, I removed both and it still doesn't work

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Person}">
            <TextBlock Text="{Binding Name}"
                       TextTrimming="CharacterEllipsis"
                       Margin="100,0,0,0"
                       Width="200"/>
    </DataTemplate>
</Window.Resources>

<Grid>
    <ItemsControl ItemsSource="{Binding Persons}"/>
</Grid>

Clarification

This works perfectly when the text is too big but I want it to work when the window is getting resized to a smaller width too.

Omri Btian
  • 6,499
  • 4
  • 39
  • 65
  • 1
    WOW! You're only now mentioning that crucial part of your problem??? After 4 people have spent half an hour trying to help you? – Sheridan Aug 19 '14 at 08:49
  • @Sheridan I'm sorry. I have a bit of a problem explaining my self sometimes :/ – Omri Btian Aug 19 '14 at 08:50
  • Actually, I've just tested that and that doesn't make a difference either... I'm having trouble *not* making it work... even *with* a `StackPanel` as the `ItemsPanelTemplate`. – Sheridan Aug 19 '14 at 08:51
  • @Omribitan How is the Person class defined? How is the list defined, and where is it defined? – Stígandr Aug 19 '14 at 08:58

4 Answers4

3

DataTemplate won't pick the style from window since it does not lie in that scope. Move the style either inside DataTemplate.Resources Or Application.Resources so that it can be picked by TextBlock inside DataTemplate.

Second, you have wrapped TextBlock inside StackPanel which gives it infinite size to expand. So, remove Stackpanel which is wrapping TextBlock.

Third, constraint width of ItemsControl or set MaxWidth as you feel like.

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Person}">
        <DataTemplate.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
            </Style>
        </DataTemplate.Resources>
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Persons}" Width="30">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

UPDATE:

In case you want to make it work for re-size of window, instead of setting width, set max width on TextBlock:

<Window.Resources>
    <DataTemplate DataType="{x:Type local:Person}">
        <TextBlock Text="{Binding Name}" MaxWidth="200"
                    TextTrimming="CharacterEllipsis"/>
    </DataTemplate>
</Window.Resources>
<ItemsControl Margin="100,0,0,0" ItemsSource="{Binding Persons}"/>
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
1

add x:Key to the style and set TextBlock's Style like this:( Rohit Vats has said the reason)

<Style x:Key="tb" TargetType="{x:Type TextBlock}">
    <Setter Property="TextTrimming" Value="CharacterEllipsis"></Setter>
</Style>

<DataTemplate DataType="{x:Type local:Person}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Width="90" Style="{DynamicResource tb}" Text="{Binding Name}"
               Margin="100,0,0,0"/>
    </StackPanel>
</DataTemplate>

and then remove stackpanel or set textblock's width.

result:

enter image description here

and my test code is :

            Persons = new List<Person>();
            Person p = new Person();
            p.Name="One\ntwo two\nThree Three Three\nfour four four four";
            Persons.Add(p);

another result:(resize the window)

enter image description here

code:

<DataTemplate DataType="{x:Type local:Person}">

                <TextBlock Style="{DynamicResource tb}" Text="{Binding Name}"
                       Margin="100,0,0,0"/>

        </DataTemplate>
Rang
  • 1,362
  • 7
  • 17
  • 30
0

That's a pretty bold statement and an untrue one at that. Without even copying your code into a new project, I can see why you have that problem. In order for the CharacterEllipsis to work, the TextBlock needs to have some constraint put on its Width... otherwise, how would WPF know when to start the character ellipsis effect?

One solution would be to set an exact Width on the TextBlock:

<TextBlock Text="{Binding Name}" Margin="100,0,0,0" Width="200" />

Of course, that won't be convenient for many people, so an alternative would be to not use the StackPanel as the ItemsPanelTemplate (or in the DataTemplate) because they will let the TextBlock grow infinitely.


UPDATE >>>

Ok, you have three possible solutions because the Style is out of scope of the generated DataTemplate elements:

a) Move the Style into the DataTemplate.Resources:

<DataTemplate DataType="{x:Type local:Person}">
    <DataTemplate.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="TextBlock.TextTrimming" Value="CharacterEllipsis" />
        </Style>
    </DataTemplate.Resources>
    <TextBlock Text="{Binding Name}" Margin="100,0,0,0"/>
</DataTemplate>

b) Add the TextTrimming property directly to the TextBlock:

<TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis" Margin="100,0,0,0"/>

c) Set the Style on the TextBlock explicitly:

<Style x:Key="YourStyle" TargetType="{x:Type TextBlock}">
    <Setter Property="TextBlock.TextTrimming" Value="CharacterEllipsis" />
</Style>

<TextBlock Style="{StaticResource YourStyle}" Text="{Binding}" Margin="100,0,0,0"/>
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • I didn't mean to state that it doesn't work, I meant it doesn't work for me. Also, as I said in my post I've tried that and it still didn't work. I've also removed the stackPanel as the `ItemsPanel` and it still doesn't affect – Omri Btian Aug 19 '14 at 08:29
  • Ok, that's unusual... give me a moment to copy it to a new project to test. – Sheridan Aug 19 '14 at 08:32
  • It *does* work... perhaps *you* should try it in a new project... clearly you are either *not* following this correct advice, or you have additional elements that are interfering with the normal behaviour. I have tested it in a new project and can confirm that all three of these solutions *do* work. Make sure that you remove the `StackPanel`s as originally suggested. – Sheridan Aug 19 '14 at 08:46
  • Sorry for not being clear earlier. It does work when the text is too big but I'm looking for a way to crop the text when the window resizes to a smaller width ... – Omri Btian Aug 19 '14 at 08:48
0

Short answer:

Remove your stackpanel in your datatemplate:

    <DataTemplate DataType="{x:Type local:Person}">
            <TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis"/>
    </DataTemplate>

The stackpanel took whatever space it wanted, and thus the trimming was not working.

Long answer:

Example of setting datacontext:

<Window.DataContext>
   <local:PersonsViewModel/>
</Window.DataContext>

Simple vm:

public class PersonsViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Person> persons = new ObservableCollection<Person> { new Person { Name = "Bjarne balblablalblalbal balbalbalballblalbla" }, new Person { Name = "Arne Belinda blblabllalbalblllablalbla Arne Belinda blblabllalbalblllablalbla Arne Belinda blblabllalbalblllablalbla Arne Belinda blblabllalbalblllablalbla Arne Belinda blblabllalbalblllablalbla" }, new Person { Name = "Turid" } };
    public ObservableCollection<Person> Persons
    {
        get { return persons; }
        set
        {
            if (Equals(value, persons)) return;
            persons = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator] // No R#? Comment this line out
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Person class must also implement INotifyPropertyChanged to signal change of the property..

public class Person : INotifyPropertyChanged
{
    private string name;
    public String Name
    {
        get { return name; }
        set
        {
            if (value == name) return;
            name = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Cheers

Stian

Stígandr
  • 2,874
  • 21
  • 36
  • Please see the edit and the comments on the rest of the answers. it doesn't work. – Omri Btian Aug 19 '14 at 08:42
  • @Omribitan I was a bit slow on my post button here, phone rang and Rohit was faster. Anyways this works just fine here. Read his comments regarding the stackpanel. It won't wrap because it consumes all space avaliable. Are you sure you have content in your list? Does your list implement INotifyPropertyChanged or is it a DO? – Stígandr Aug 19 '14 at 08:44