WPF ListView->GridView->StackPanel - c#

I have a ListView that uses GridView to display some data. One of the fields contains a list with image paths. Therefore I defin a GridViewColumn and create a DataTemplate. Dis DataTemplate contains another ListView with the Images list as new DataContext. When I don't write anything in the inner StackPanel, I can see that a list of string (in the format AppName.ClassName) is displayed in left to right order.
But whenever I try to display the strings as something else, eg
<Image Source="{Binding Name}" Height="32"/>
I get an System.Windows.Markup.XamlParseException . Even with data binding I get an exception. Eg
<Image Source="Images/Camera_32xLG.png" Height="32"/>
. Any hint, what I might do wrong?
<GridViewColumn Header="Images">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Images}" BorderThickness="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
--> here is where I don't know what to do next
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Since the StackPanel is a part of ItemsPanelTemplate, you should just define it's properties and not explicitly add any children. The way to specify appearance of each item is through the ListView.ItemTemplate property:
<ListView ItemsSource="{Binding Images}" BorderThickness="0">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Name}" Height="32" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Related

How can i make a ListView's items take up all the available height?

I am trying to make a column chart using WPF. For the Y axis I have a list of values which I would like to display on the control.
I have a ListView bound to the collection. How can I get the items to spread over the entire length of the list view rather then squish together at the top? And is the ListViewthe correct control to use for this?
Here is a sample of my Xaml:
<ListView Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"
ItemsSource="{Binding YAxisValues}"
Background="Gray" VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Value}"
Foreground="White"
HorizontalAlignment="Left"
FontSize="12" Width="50"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
On the left is the list view as i currently have it.
On the right is my desired result.
How can I change my ListView to get there? Or do I need to use a different control entirely?
with UniformGrid used as ItemsPanel items get equal height
<ListView Name="Axis" Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"
ItemsSource="{Binding YAxisValues}"
Background="Gray" VerticalContentAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<!--no changes-->
</ListView.ItemTemplate>
</ListView>
there can be a issue when ListView doesn't have enough height for all elements. In that case I would put ListView into ViewBox
Set HorizontalContentAlignment to Stretch for items.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>

How do I limit the Image size to its parent container

I am doing my first WPF-Project with the MVVM-Model. I have got two views that i want to look like that:
But sadly the images do not shrink to parent size, they stay in original size:
Views.PictureList
<UserControl x:Class="BIF.Views.PictureList"
xmlns:view="clr-namespace:BIF.Views"
d:DesignHeight="120" d:DesignWidth="300">
<ListBox ItemsSource="{Binding List}" <!-- List<PictureViewModel> -->
ScrollViewer.VerticalScrollBarVisibility="Hidden"
SelectedItem="{Binding CurrentPicture, Mode=TwoWay}" SelectionMode="Single">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<view:Picture DataContext="{Binding}" />
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Views.Picture
<UserControl x:Class="BIF.Views.Picture"
d:DesignHeight="200" d:DesignWidth="200">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="4">
<Image Source="{Binding FilePath}"/>
</Border>
</UserControl>
I have already tried to set height of view:Picture manualy by adding:
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=ActualHeight}"
But thats not working 100% correct and I also do not want to set a fix height, because I want the PictureList to be resizeable.
Any suggestions are welcome.
You have to set ScrollViewer.VerticalScrollBarVisibility to "Disabled" since the "Hidden" value gives the content infinite space in the vertical direction, that's all.
StackPanel does not limit the size of container and hence all the space is available to its child elements.
You should either set limits to your stack panel or use a better control for this case, may be a Grid.
Let me know if you need help in that.
Two litte changes and everything works wonderfull now.
ScrollViewer.VerticalScrollBarVisibility="Disabled"
No ListItem in the DataTemplate
<ListBox ItemsSource="{Binding List}" <!-- List<PictureViewModel> -->
ScrollViewer.VerticalScrollBarVisibility="Disabled"
SelectedItem="{Binding CurrentPicture, Mode=TwoWay}" SelectionMode="Single">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- No ListItem here -->
<view:Picture DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thank you guys!

c# WPF TreeView in ListView via CellTemplate

I am new to WPF and XAML..
I want to add an TreeView into a ListView Element with a CellTemplate..
I want to bind each ListViewItem to a Custom class called "Symbol"
This Class has an Property called "Name" and a Property called "Images".
"Name" is just a String, which should be the root Element of the TreeView..
"Images" is a List of Strings.
Each entry of this list should be an Children of this TreeView..
And please do not just leave a code snippet, i want to understand how CellTemplates work!
Thank you!
<Grid>
<ListView x:Name="listview" HorizontalAlignment="Left" Height="326" Margin="0,33,0,0" VerticalAlignment="Top" Width="499">
<ListView.View>
<GridView>
<GridViewColumn Header="Symbols" Width="200" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TreeView>
<!--
what to be done here?
-->
</TreeView>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="250" Margin="504,33,0,0" VerticalAlignment="Top" Width="250">
<Border x:Name="image_preview" HorizontalAlignment="Center" Height="250" VerticalAlignment="Center" Width="250"/>
</Border>
</Grid>
First you should bind ListView to a collection of Symbol objects.
Now, every cell of your ListView is bound to Symbol object. If I understand you correctly, each Symbol should be a TreeView with root node header displaying Name property and collection of children displaying Images strings.
This can be achieved this way:
<TreeView >
<TreeViewItem Header="{Binding Name}" ItemsSource="{Binding Images}" />
</TreeView>

Tile Grid with Bindings?

OK, what I'm trying to do is fairly simple :
I'm getting a list of images (using bindings) which I'm trying to display in a table-like grid (like 3 images per row)
How can this be done?
<ListBox.ItemTemplate>
<DataTemplate>
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding AlbumArt}"/>
</DataTemplate>
</ListBox.ItemTemplate>
This way, the images are property display, but not the way I want them to - they are display one below the other and not like :
A B C
D E F
G H I
How can this be done? Any ideas?
A great solution would be using UniformGrid with its columns property and ItemsControl.
Example:
<ItemsControl ItemsSource="{Binding AlbumArt}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This way you will get the desired result. Read more about UniformGrid here: MSDN
The reason why your solution does not work, is that Listbox panel puts items one under another, whereas UniformGrid puts them from left to right, until there is available space or has hit the columns limit and then goes down the row.
You can use two StackPanels, one with verticle orientation and one with horizontal. Here's your code edited to include them:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Verticle">
<StackPanel Orientation="Horizontal">
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding AlbumArt}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

An ItemsControl containing UserControl elements

I'm kind of shooting in the dark on this one and have been looking around but couldn't find much of anything related. Pretty much I am trying to create an ItemsControl on a current Window that I've got, so when the user clicks an "Add Product" button on the window, it will add a UserControl to the screen in a horizontal matter.
For starters I am using an MVVM pattern and I have a PricingViewModel which is my ViewModel for the MAIN window. I have a second view model named ComparisonViewModel, which is the ViewModel for the View of the UserControl that I would like to show everytime the user hits the "Add Product" button on the PricingView. Jumping into my code, I've got a declared ObservableCollection and my AddComparison method. The Collection is instantiated in the constructor of the VM.
public ObservableCollection<ComparisonViewModel> Products { get { return _products; } }
public void AddComparison()
{
var products = IoC.Get<ComparisonViewModel>();
Products.Add(products);
}
Next, I've got and ItemsControl in the PricingView that binds to that collection in the PricingViewModel:
<ItemsControl ItemsSource="{Binding Path=Products}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
I run it and after hitting add, it just shows the collection name. How can I actually get it to Pop up with a new Comparison User Control when the user hits Add Comparison? Thanks a ton for the help in advance!
You'll want to set the ItemTemplate so the ItemsControl knows how to render each item in the collection (by default, it is just displaying the result of calling .ToString()).
<ItemsControl ItemsSource="{Binding Path=Products}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type namespace:ComparisonViewModel}">
<!-- EXAMPLE -->
<Border BorderBrush="Black"
BorderThickness="2">
<DockPanel Orientation="Horizontal">
<TextBlock Text="{Binding ComparisonResult}"
DockPanel.Dock="Right" />
<TextBlock Text="{Binding Name}"
DockPanel.Dock="Left" />
</DockPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have found that I needed to tell the ItemsControl two things... First is what type of "thing" the ItemsControl is:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
And the second is how to display the Control:
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:Widget Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
The final code looks like:
<ItemsControl ItemsSource="{Binding Path=DynamicItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:Widget Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You also need to add a reference to your control namespace in the window declaration stuff:
xmlns:c="clr-namespace:IHateEverything.Controls"

Categories

Resources