How do I wrap content in a WPF ListView? - wpf

I have a very simple WPF ListView that I'm using to list blocks of text. I'd like it to scroll vertically, but the text should wrap so that there is no horizontal scroll. All the examples I've seen are overly convoluted DataGridView nesting solutions. This seems like such a simple use-case, however. Here is my current code:
<ListView
Height="Auto"
Width="Auto"
Margin="0"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"/>
I've tried setting the ScrollViewer.HorizontalScrollBarVisibility and HorizontalContentAlignment properties but the text simply runs off the end of the control and doesn't wrap.
Each item is added to the ListView.Items collection and is a ListViewItem object. The text is set to the item's Content property.
Here is the code responsible for adding text times to the list:
ListViewItem item = new ListViewItem();
item.Content = "Item text is set here, but refuses to wrap in list view!";
mLogListView.Items.Add(item);
Thank you.

This should be what you need
<ListView Margin="12,23,309,191"
Name="mLogListView"
FontWeight="Bold"
FontSize="16"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch" >
<!-- here set the itemTemplate to a TextBlock that can wraps-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.}" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Note the syntax Text="{Binding Path=.}" that is equivalent to Text="{Binding}". This is called empty binding syntax.
In this case Text is bound to the entire ListViewItem object. The empty binding syntax is useful when you want to bind to the entire object item instead of just to single property of the item.
This is convenient for the example because the source object (the ListViewItem) is of type string and you simply want to bind to the string itself.
For more information see msdn at section Specifying the Path to the Value

I wanted to view images in a ListView, it displays by default only one column. To prevent this, you can insert the following code:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="0" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Now displays ListView, instead of one column, just one line :-(
To prevent this, you can insert this line of code:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
So it could look something like this:
<ListView ItemsSource="{Binding YourItemsSource...}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border ... and so on ...
I hope, it can help someone
;-)

Related

Bound String List displays containing class name not the string

My Problem is the following:
I have a class which has a ObservableCollection of strings, which gets populated by the selected children.
Those are supposed to be listed in a ListBox.
But the strings aren't listed, rather the object type in FilterList is shown.
<ListBox Grid.Row="2" Grid.Column="0"
ItemsSource="{Binding FilterList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ListOfActiveFilters}">
<!--<ContentPresenter Content="{Binding ListOfActiveFilters.}"/>-->
<TextBlock Text="{Binding}" />
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Filter List contains the classes which have ListOfActiveFilters as a Property.
I thought that it would work the way I showed it, but it doesn't.
Since that is also the way I saw others do it.
If I were to use a Class with a single string Property as the type of the Collection instead of the Collection of strings I have right now, I think it would work.
I just don't really see the point in creating a class which holds a string property just so that I can bind the ContentPresenter or TextBox to that property.
What am I doing wrong? I am rather new to the topic.
One single ListBox will only be able to display the filters in one single ListOfActiveFilters collection. You could use nested ItemsControls to display them all:
<ItemsControl ItemsSource="{Binding FilterList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding ListOfActiveFilters}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The other option is to modify your data model and put all strings in a single collection. You could then bind the ItemsSource property of the ListBox directly to this one. But a ListBox itself has no concept of hierarhical data.

Items Box with limit of objects in row (Large icons view style in Windows Explorer)

Can't find a solution to a pretty simple UI problem:
I have a model with a Images property. The Images property holds a collection of items Image.
As for now on - I have a ListBox and binding a ListBoxItem data template to Images.Image and all good. But I have each item on a new line. Not good.
What I am willing to achieve is, lets describe as, a Listbox with Horizontal items orientation and limit of items in a row. Just like Large icons view style in Windows Explorer.
Have somebody previously implemented such a solution? Any advice will be highly appreciated.
Thank you in advance.
Use a WrapPanel (or some other appropriate Panel) as the ListBox's ItemsPanel, and disable horizontal scrolling:
<ListBox ItemsSource="{Binding Images}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Width="100" Margin="5"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can set the ListBox's ItemPanelTemplate to WrapPanel, like this.
I am not sure why it is always like that - but as soon as I asked, I have found an alternative solution with usage of ListView:
<ListView ItemsSource="{Binding Images}">
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Image}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>

Listbox reversed items order

I've spend couple of hours trying to reverse the order of listbox (bottom to top) as described on the picture:
That means that newly added items should be inserted at the top of the listbox. I do not understand that something so trivial can be so difficult to implement in wpf...
I do not want to use transient effects on panel and items itself because it causes strange behavior on scrollviewer. I can not use some sort definitions on ICollectionView because I want to use a data virtualization which provides ordered data and I have to add them as is.
This is my Listbox (ListView) definition:
<ListView ItemsSource="{Binding Collection}"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.ScrollUnit="Pixel"
ScrollViewer.IsDeferredScrollingEnabled="True"
IsSynchronizedWithCurrentItem="True"> <!--To manage scrolling from view model using ICollectionView.ScrollTo()-->
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
<!--To auto scroll to bottom (via calling ICollectionView.ScrollToBottom()-->
<i:Interaction.Behaviors>
<Behaviors:ScrollIntoCurrentItemBehavior />
</i:Interaction.Behaviors>
<!--To pin listbox panel to bottom-->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Is there any acceptable solution for that? I really appreciate any help! thanks

Silverlight 4 - simple control template

<DataTemplate x:Key="dirtSimple">
<TextBlock Margin="10,0,0,0" Text="{Binding Path=CurrentBook.Published, StringFormat=d}"></TextBlock>
</DataTemplate>
<ControlTemplate x:Key="lbWrapPanelTemplate">
<StackPanel Orientation="Horizontal" Margin="2" Background="Aqua">
<ItemsPresenter></ItemsPresenter>
</StackPanel>
</ControlTemplate>
...
<ListBox Template="{StaticResource lbWrapPanelTemplate}" x:Name="bookListBox" Grid.Row="0" ItemsSource="{Binding Path=BookSource}" ItemTemplate="{StaticResource dirtSimple}" >
</ListBox>
The list box is displaying correctly, with a beautiful "Aqua" background, and each item is boringly displayed with just a date. For some reason though the items are not flowing horizontally. I originally tried it with the Silverlight Toolkit's WrapPanel, with the same problem, but I can't even get it to work with a built-in StackPanel, so I suspect I'm missing something.
Are you trying to get selection-based behavior that a ListBox provides? If not, use an ItemsControl (and supply an ItemsPanel as below).
The reason it's not going horizontal is the ItemsPresenter ultimately has its own panel it lays out items in. It's not inserting each item separately into your StackPanel (or WrapPanel), it's putting them in its own panel
What you want to do is specify a value for ItemsPanel like so:
<ListBox ItemTemplate="{StaticResource dirtSimple}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

WPF Error: "Items collection must be empty before using ItemsSource."

Does anyone know why I keep getting the "Items collection must be empty before using ItemsSource"-Error?
Here is the code:
<ScrollViewer Margin="8,8,8,8" Grid.Row="3" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<WrapPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding}" x:Name="CustomerList" >>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal">
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<View:UserControlCustomerDetails>
</View:UserControlCustomerDetails>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
</ScrollViewer>
This is what I do in my Code-Behind:
CustomerList.ItemsSource = _mainViewModel.CustomerCollection;
Note that CustomerCollection is just a simple List<Customers>.
Thanks for your help!
Cheers
Is this code copied verbatim? Do you really have two right angle brackets (>>) at the end of the <ItemsControl... line? If so, the second right angle bracket might be getting treated as text content, which is getting added to the Items collection.
First, remove ItemsSource="{Binding}" from your ItemsControl. This should fix your error i believe.
Secondly, I'm not sure if your WrapPanel is going to work as expected in this case. From my understanding, WrapPanel will do wrapping when it has multiple children that extend out of bounds. In this case, your WrapPanel only has 1 child, an ItemsControl.
Apparently you're using the MVVM pattern. In that case you shouldn't explicitly assign a collection to the ItemsSource property... instead, you should assign a ViewModel to the DataContext of the Window (or UserControl). If your DataContext is _mainViewModel, your binding should be :
<ItemsControl ItemsSource="{Binding CustomerCollection}" ...
Use DataGrid.Items.Clear();
I hope it will be Helpfull...

Resources