GridView width based on ItemsSource - c#

I am currently using a GridView to display a list of images that the user can swipe through. When they get close to the end of the list, new images load through the use of a ObservableCollection that implements ISupportIncrementalLoading.
How do I change the cell size to match the size of the image? The images are sometimes in Portrait, and sometimes in Landscape, and sometimes in an non-uniform aspect ratio; however, the GridView insists on all the cells being the same width.
e.g. if I go with the following:
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemsGridView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.RowSpan="2"
Padding="116,136,116,46"
SelectionMode="None"
DataFetchSize="10"
IncrementalLoadingThreshold="5"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
IncrementalLoadingTrigger="Edge"
IsSwipeEnabled="false">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,5,0"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
I end up with all the times being the same width as the first image. If I try to set the image width (I have a databound property that returns the image width), some of the images end up being less wide, but the cell they are in is still the same width as everything else.
<Image Width="{Binding ImageWidth}" Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
Setting the width on any item in the hierarchy doesn't seem to help - even taking this to the extreme doesn't help at all - e.g.
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="{Binding ImageWidth}">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="{Binding ImageWidth}">
<Image Width="{Binding ImageWidth}" Source="{Binding Image}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,5,0"/>
</StackPanel>
</Grid>
</DataTemplate>

There are two ItemsPanelTemplate-s that supports incremental loading: VirtualizingStackPanel and WrapGrid.
WrapGrid does not allow different items' size.
VirtualizingStackPanel allows variable size of items but displays items in one row/column.
So if you want a different layout you need a custom implementation of VirtualizingPanel.
But I do not understand what do you want exactly. If you want a grid then all items in a row or column will have the same height or width. Do you want a virtualizing VariableSizedWrapGrid?

Take a look at the VariableSizedWrapGrid
try to add this xaml to your GridView declaration:
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>

Related

window phone 8.1 build app for different screen size

I'm newer in window phone.
So, i use visual studio 2013 to build first app for window phone 8.1.
I test on emulator WVGA 4 inch, everything is ok.
this is my simple xaml:
<Grid>
<ScrollViewer>
<StackPanel>
<TextBlock x:Name="tbCheck" Margin="10,0,0,0" FontSize="20" Text="check"/>
<ListView x:Name="lvInfo" SelectionChanged="lvInfo_SelectionChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="5" Orientation="Horizontal" HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderThickness="3" CornerRadius="3" Margin="10,0,10,10" BorderBrush="#ffffff">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Image Margin="5,5,5,5" Width="100" Height="100" HorizontalAlignment="Left" Source="{Binding ImgInfo}"/>
<StackPanel>
<TextBlock FontSize="28" Text="{Binding NameInfo}"/>
<TextBlock Margin="0,5,0,5" FontSize="18" Text="{Binding AgeInfo}"/>
<TextBlock FontSize="18" Text="{Binding GenderInfo}"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</ScrollViewer>
i know i need to fix for different screen size to make everything like on WVGA 4 inch, but i don't know how to do that.
Please help me.
Few things to point out.
1) Windows Phone OS Automatically sets the FontSize of Items based on the Font Size of OS. You do not need to explicitly Set the FontSize of TextBoxes. However if you want to make FontSize of your items explicitly larger or smaller than others, use Theme Resources
See Table Below:
2) Your first StackPanel Inside DataTemplate HorizontalAlignment is set to Left. Unless it is required by Design, Do not use it. Instead use a Grid
Replace your StackPanel with Grid as below.
<Border BorderThickness="3" CornerRadius="3" Margin="10,0,10,10" BorderBrush="#ffffff">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Margin="5" Width="100" Height="100" Source="{Binding ImgInfo}"/>
<StackPanel Grid.Column="1">
<TextBlock FontSize="{StaticResource PhoneFontSizeLarge}" Text="{Binding NameInfo}"/>
<TextBlock Margin="0,5" FontSize="{StaticResource PhoneFontSizeSmall}" Text="{Binding AgeInfo}"/>
<TextBlock FontSize="{StaticResource PhoneFontSizeSmall}" Text="{Binding GenderInfo}"/>
</StackPanel>
</Grid>
</Border>
Now your ListViewItem will consume full space on device irrespective of ScreenSize and looks same on all resolutions.

Modify last (or individual) item inside GridView

I have a GridView which is populated (through binding) by an ObservableCollection. How do I set it up so that every time a new item is added to the ObservableCollection, the last item in the GridView always has a button on top of it ?
This is the XAML of the GridView's ItemTemplate
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="White">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding DateMade}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
My problem lies in this template being applied for all items in the GridView. I want it so that if it's the last item (and the last item would keep changing every time a new item is added), the above StackPanel should be replaced by another control (say, a button). How would I go about doing this ?
I would extend the template of all elements but hide the additional element and only show it if it's the latest element (specified by some bool property that is set to true on the last element). Something like this.
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="White">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<Button Visibility="{Binding IsLastElement, Converter={StaticResource BoolToVisibilityConverter}}"/>
<StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding DateMade}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
I think another option is to change the DataTemplate dynamically using TemplateSelecting event, on changing content of elements, but it would be a little bit more work.
There might be better solutions though.
Edit
Decided to share some links for the aforementioned idea (Which I've used in WinRT) and another one available in WPF
WPF Based Dynamic DataTemplateSelector - used similar approach in WinRT
DataTemplateSelector - tried slightly modified example and works fine

Binding Text on TextBlock not show the whole text windows phone 8

I've got an issue that the TextBlock not showing fully while the string is more than 1000 characters.
I've tried use this code
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
or
VerticalAlignment="Stretch" on my TextBlock
or use this code
<ListBox ItemsSource="{Binding ArticleDataDetail}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding TaxoName}" Style="{StaticResource PhoneTextNormalStyle}" Foreground="#FF2976B9"/>
<TextBlock Text="{Binding Title}" FontWeight="Bold" TextWrapping="Wrap" Style="{StaticResource PhoneTextTitle3Style}"/>
<Image Source="{Binding Picture}" Width="auto" Name="articleImage" Margin="10"/>
<TextBlock Text="{Binding Content}" TextWrapping="Wrap"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But It still not show.
my code:
<Grid Margin="12,0,12,0" DataContext="{Binding ArticleDataDetail[0]}">
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<StackPanel>
<TextBlock Text="{Binding Content}" TextWrapping="Wrap" VerticalAlignment="Stretch"></TextBlock>
<TextBlock Text="GeuT"></TextBlock>
</StackPanel>
</ScrollViewer>
</Grid>
Do you mean the TextBlock in the ItemTemplate? If it's the case maybe this helps:
Set the HorizontalContentAlignment attribute of the ListBox to "Stretch":
<ListBox ... HorizontalContentAlignment="Stretch"></ListBox>
I'm just guessing what your problem is, so if it's not the case I think you should make your question clearer: rephrase it or add some illustrating images.
Another thing I could think of - without a screenshot - is that maybe the Textblock is too small to fit all the content and that it would have to be scrollable.
Scrollbars don't appear automatically if the text exceeds the display item size limits. You can enable them by adding the following properties to your TextBlocks:
ScrollViewer.VerticalScrollMode="Auto" ScrollViewer.VerticalScrollBarVisibility="Visible"

Dynamic height of StackPanel in ListBox custom ItemTemlate, WP8, C#, WPF

I'm programing app that will display data from RSS feed. I need just little view to show small image and description.
I have custom ListBox with one stackPanel where is an and .
Problem is: each item in that listbox has some height, but i need that height to change dynamically by the length of text and size of image.
There's my ListBox:
<ListBox x:Name="gui_listNovinky" SelectedIndex="-1" Height="500" VerticalAlignment="Top" ScrollViewer.VerticalScrollBarVisibility="Hidden" HorizontalContentAlignment="Stretch" >
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,1,0,0" BorderBrush="Black" Margin="10">
<StackPanel Name="stackpanel" Orientation="Horizontal" Height="500">
<StackPanel Width="435" Height="1000">
<Image Source="{Binding Image}" Height="200" Width="230" VerticalAlignment="Top"/>
<TextBlock Text="{Binding Description}" MaxHeight="290" FontSize="20" VerticalAlignment="Top" Foreground="Black" TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And there is how it look like. You can see that annoying free space below the image and the text. So ugly... :(
I will so thankful for solution. :)
PS: If there is mistakes in my English, dont be afraid to ask and i will explain it. :)
Do not enforce size inside data template. Modified DataTemplate which will solve the problem.
<DataTemplate>
<Border BorderThickness="0,1,0,0"
BorderBrush="Black"
Margin="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Image Source="{Binding Image}"
Height="200"
Width="230"
VerticalAlignment="Top" />
<TextBlock Text="{Binding Description}"
MaxHeight="290"
FontSize="20"
Grid.Row="1"
VerticalAlignment="Top"
Foreground="Black"
TextWrapping="Wrap" />
</Grid>
</Border>
</DataTemplate>

Aligning TextBlock Vertically Inside StackPanel

In my WPF application I have a DataGrid with multiple DataGridTemplateColumns. One of the columns looks like this:
<DataGridTemplateColumn Header="Column" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding SomeSource}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="5"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Green" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="6" BorderThickness="2">
<StackPanel Background="Green" Width="200" Height="150">
<TextBlock Text="{Binding Title}" HorizontalAlignment="Center" FontSize="17" FontWeight="Bold" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
This produces the following output:
As you can see the TextBlock which displays the Title is not vertically centered inside the green StackPanel. How can I do that?
StackPanel doesn't have a concept of its height, so you can't vertically-align its children. You'll have to do something a bit differently.
For example, move the fixed 150-height and background from the StackPanel to its parent border -- that way, you can vertically-align the StackPanel within the Border:
<Border Background="Green" Height="150" BorderBrush="Green" HorizontalAlignment="Center" VerticalAlignment="Center" CornerRadius="6" BorderThickness="2">
<StackPanel Width="200" VerticalAlignment="Center">
<TextBlock Text="{Binding}" HorizontalAlignment="Center" FontSize="17" FontWeight="Bold" />
</StackPanel>
</Border>
(It's not really clear why you're using that inner StackPanel since it only has one child, but I've assumed you're going to add something else to it.)

Categories

Resources