ListView: Enable text trimming instead of HorisontalScrollBar - c#

I tried to search Google, but i cannot formulate it clearly enough.
So idea is: if text cannot be displayed fully in a TextBlock, end of text should be removed and '...' should be added. For fixed size i can write something like this:
DetailsListView.Items.Add(string.Format("{0}.{1} - {2}...", i + 1, j + 1, somestring.Remove(15)));
but for dynamic WPF layout that looks ugly.
What the best way to do it?
i'm trying this one, but it doesn't work
<ListView Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" Margin="5" Name="TaskListView">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
just a scrollbar appears

No need to do it yourself, TextBlock can already do this for you:
<TextBlock TextTrimming="CharacterEllipsis"/>
It seems your text is in a list of some sort you need to set this on the TextBlock in a DataTemplate for each item in the list, e.g.:
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock TextTrimming="CharacterEllipsis"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Of course if your TextBlock is in a pane that grows as it needs then there is nothing to trim - you can set a fixed size on your TextBlock, or your ListView and disable horizontal scrolling.

<TextBlock
TextTrimming="WordEllipsis" TextWrapping="NoWrap"
FontSize="14">
One<LineBreak/>
two two<LineBreak/>
Three Three Three<LineBreak/>
four four four four<LineBreak/>
Five Five Five Five Five<LineBreak/>
six six six six six six<LineBreak/>
Seven Seven Seven Seven Seven Seven Seven
</TextBlock>
TextBlock.TextTrimming

Related

How do I keep a specific xaml element within the window (so it doesn't overflow through the bottom)

I'm trying to make a simple invoicing application as part of an assessment. I have made a interface with a listbox that contains all the items that have been requested. However when I add too many items, the listbox then flows through the bottom of the window and I have to resize the window to fit.
I've tried a dockpanel, and I've assigned the stackpanel to the grid itself. If I set a fixed height it seems to work as expected.
Here is the xaml of the listbox:
<StackPanel Grid.Column="1" Grid.Row="0" ClipToBounds="True">
<ListBox Name="Shirts" HorizontalContentAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="5" ClipToBounds="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding ShirtSize}" />
<Run Text="{Binding ShirtStyle}" />
<Run Text="{Binding ShirtColour}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Print Invoice" Margin="5" ClipToBounds="True"/>
</StackPanel>
I expected the code to work like this (it's not meant to be of fix height but it works as an example).
How it actually works.
Use a DockPanel instead of a StackPanel and it should work better. StackPanel will grow with its content regardless of its container size. A DockPanel will respect the container size and fill the available space. Put the button first in order with Dock="Bottom" and then the ListBox with Dock="Fill" (the list will arrange itself above the button even though it is declared after it, which is a bit unintuitive)

How to make ListViewItem share the same height and scale automatically

I have a ListView in a Grid inside a MainWindow, and it has defined a DateTemplate inside of the ItemTemplate, which includes a TextBlock, each TextBlock has a different length of text, some are long, and some short.
The application needs to fit different screen resolutions, that is, the FontSize of each TextBlock needs to be autoscaled accordingly.
So I wrap the TextBlock with a ViewBox, but the problem is, the short text will get a bigger FontSize than the long text, I want all TextBlock's can share the same FontSize and can autoscale to fit different screen size and resolution, any idea?
My ListView is as below:
<ListView x:Name="specs" Margin="10 15 10 15" VerticalAlignment="Center"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="Transparent" BorderThickness="0">
<ListView.ItemTemplate>
<DataTemplate>
<Viewbox>
<TextBlock Text="{Binding}" TextWrapping="Wrap" FontFamily="Kaiti Regular"/>
</Viewbox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You can use a shared size group to force the textblocks all to have the same width as the widest one, which in turn will force the Viewboxes to scale identically.
The key things here are Grid.IsSharedSizeScope="True" on the ListView, and putting the content of the ViewBox in a grid column with SharedSizeGroup="SomeArbitraryString". Under a given parent that's a shared size scope, all the grid columns in a particular named shared size group will have the same width as the widest one (and the same for grid rows and height).
<ListView
x:Name="specs"
Margin="10 15 10 15"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Words}"
Grid.IsSharedSizeScope="True"
>
<ListView.ItemTemplate>
<DataTemplate>
<Viewbox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="Text" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Text="{Binding}"
TextWrapping="Wrap"
FontFamily="Kaiti Regular"
/>
</Grid>
</Viewbox>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm not convinced this will resolve the entire issue, but it'll get you another step along. And in general, it's a wonderfully useful tool for DataTemplate layout in ItemsControls.

ListView with columns and bindings performance

I have performance issue with ListView:
Single item takes 13-30 ms to create (50 items is over 1 second). Virtualization (recyling mode) is on, but scrolling even 100 items is already very uncomfortable.
At first I thought it's layout problem. But the reason seems to be - bindings.
There are multiple columns and each column cell has different template with different bindings, as an example:
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Value}"
Visibility="{Binding IsEditable, Converter={local:TrueToCollapsedConverter}}" />
<Grid local:GridBehavior.Columns=",auto"
Visibility="{Binding IsEditable, Converter={local:FalseToCollapsedConverter}}">
<TextBox Text="{local:ExceptionBinding Path=Value, Converter={local:DoubleToStringConverter}}"
local:TextBoxBehavior.SelectAllOnFocus="True"
local:ListBoxBehavior.SelectListBoxItemOnFocus="True" />
<TextBlock Grid.Column="1" Text="{local:Lng Key=Unit.mm}" />
</Grid>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
Any single binding add something like 0.1 ms. There are 20 columns, each cell has from 1 to 20 bindings, so it leads to this:
Binding take majority of time, e.g. 2.83 of 3.07 ms for the first column on screenshot.
Is there a way to gain some performance? Am I doing some obvious mistake?

Display data from two levels down

I have the following classes, which contain ObservableCollections of the next level down:
Draw
ObservableCollection<Round>();
Round
ObservableCollection<Formation>();
Formation
So a Draw is made up of Rounds, Rounds are made up of Formations.
I have a page which has a button to create a random draw, I currently have it calling another class which returns a draw:
this.defaultViewModel[DrawName] = RandomDraw.generate();
I am having no problem binding a ListView to Rounds and displaying round information, but how do I display the individual formations? This is what I am currently doing, I was not expecting to be able to just display things by binding to Formations but how do I access it?
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<TextBlock
Text="{Binding Formations}"
TextWrapping="WrapWholeWords"
Pivot.SlideInAnimationGroup="2"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemContentTextBlockStyle}"
Margin="0,0,19,0"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You should take a look at Hierarchical Data Templates, which are used by the WPF TreeView control rather than ListViews. They are a natural fit to show hierarchical data. Of course, like any WPF control, you can completely customize their appearance using styling and templates. Here are some good references:
MSDN How to: Use a TreeView to Display Hierarchical Data
Hierarchical Databinding in WPF
However, if you would like to keep using ListViews, then one way to do this is to nest another container control inside the parent ListVIew. ObservableCollections are processed automatically by specific WPF elements, such as Panels. In your example, you can replace the second TextBlock with another ListView, with an ItemTemplate similar to the first. It can also be any Collection-like Panel element, such as StackPanel.
<ListView
ItemsSource="{Binding Rounds}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,9.5">
<TextBlock
Text="{Binding RoundNumber}"
TextWrapping="Wrap"
Pivot.SlideInAnimationGroup="1"
CommonNavigationTransitionInfo.IsStaggerElement="True"
Style="{ThemeResource ListViewItemTextBlockStyle}"
Margin="0,0,19,0"/>
<!-- CHANGED CODE HERE -->
<ListView
ItemsSource="{Binding Formations}"
...>
<ListView.ItemTemplate>...</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

ListBox Value Display in Windows Phone 8

I am trying to bind the observable collection with a ListBox and displaying the data on UI (Windows Phone 8.0).
My Listbox have four textblock for four property,
<ListBox x:Name="allListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Style="{StaticResource txtBlockStyleDate}" Text="{Binding Date}"></TextBlock>
<TextBlock Style="{StaticResource txtBlockStyle1}" Text="{Binding TypeOfApproval}"></TextBlock>
<TextBlock Style="{StaticResource txtBlockStyle2}"
Text="{Binding TypeOfRequest}" />
<TextBlock Style="{StaticResource txtBlockStyle3}" Text="{Binding Status}"/>
<TextBlock Height="30"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
all the objects in observable collection are showing fine, but when any of the property does not have any value, its text block is still there, and its space is kind of visible, which gives the bad impression over UI.
Can you suggest what should i do, when any property is blank, textblock related to that should not eat any height and next textblock should take space of it.
I am attaching an image, see after testing blank space is visible, coz its property is null, i want to remove this space.
You are going to need an IValueConverter, basically the idea is you do this:
... insert ...
<ListBox.Resources>
<VisibilityConverter x:Key="VisibilityConverter"/>
</ListBox.Resources>
... change ...
<TextBlock Style="{StaticResource txtBlockStyleDate}" Visibility="{Binding Date, Converter={StaticResource VisibilityConverter}}" Text="{Binding Date}"/>
Within your IValueConverter implementation, you just see if the property is null or empty. If it is you just return Visibility.Collapsed
You need to use a Visibility converter for this!
If your bound data is text, a StringToVisibilityConverter would be fine.
An example on how to do this can be found here: http://www.smallandmighty.net/blog/using-value-converters-to-change-the-visibility-of-a-control

Categories