Horizontal scrolling a row of ViewBox images in Xaml - wpf

I'm working on a UWP Windows 10 app with a XAML UI. One of my pages requires that images fill the height of the window (or screen in tablet mode) and uniformly scale as one long row of images from left to right (going off-screen). I've got this set up perfectly using ViewBoxes for the images inside of a StackPanel set to a Horizontal Orientation like so:
<StackPanel Orientation="Horizontal">
<Viewbox>
<Image Source="http://lorempixel.com/200/200/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/400/600/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/700/700/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/100/300/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/100/500/" />
</Viewbox>
</StackPanel>
The intention is for the images to flow off-screen with a horizontal scroll that allows the user to pan from left to right to see the gallery of images as one long row.
I've tried enabling HorizontalScrollMode on the parent StackPanel like so:
<StackPanel Orientation="Horizontal" ScrollViewer.HorizontalScrollMode="Enabled">
But this did not enable any scrolling at all.
I also tried to wrap everything inside of a ScrollViewer like so:
<ScrollViewer HorizontalScrollMode="Enabled">
<StackPanel Orientation="Horizontal">
<Viewbox>
<Image Source="http://lorempixel.com/200/200/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/400/600/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/700/700/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/100/300/" />
</Viewbox>
<Viewbox>
<Image Source="http://lorempixel.com/100/500/" />
</Viewbox>
</StackPanel>
</ScrollViewer>
But this completly breaks my ViewBox layout by shrinking all the images so they fit within a small portion of the screen and no longer fill the window/tablet height.
I've tried a number of other variations with similar results. Does anyone have some suggestions for solving this? Let me know if you need more info.

You do need a ScrollViewer to enable scrolling, although you might need to set a few properties to make it only scroll horizontally as mentioned in Windows 8 ListView with horizontal item flow
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.ZoomMode="Disabled"
Now the Viewbox is not the most controllable... control. You could try using the
SquareGrid panel from my toolkit instead of the Viewboxes. Maybe simplify it a bit. If that isn't enough - you could add some bindable properties that would update when the size of your window changes and bind the Width and Height of these images to these properties. Note that you can't use ActualWidth or ActualHeight because these don't raise change notifications on size changes.

<GridView x:Name="ImageGridView"
SelectedItem="{x:Bind ViewModel.SelectedLocation, Mode=TwoWay}"
Margin="10,0"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.HorizontalScrollMode="Auto"
Grid.Row="4" Grid.ColumnSpan="5"
ItemsSource="{x:Bind ViewModel.CheckedLocations}"
ItemContainerStyle="{StaticResource PinsGridViewItemStyle}"
ItemTemplate="{StaticResource ImageOverlayGalleryFolderDataTemplate}" >
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="1"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
This is my code to show 1 row of photos. You can adjust by the MaxiumRowsOrColumns. Also note that both HorizontalScrollBarVisibility and HorizontalScrollMode are present to custom as you want to.

Related

Changing Height of ScrollViewer Content dynamically through code

I'm stuck at a point where I have to change the height of scroll viewer content irrespective of the size the contents inside it need.
The reason is that I will have a very long Image and I don't want to slow my GUI while scrolling. So,I cut the long image and I render stitched images of it depending on current scrollviewer vertical offset.
I tried to achieve it by putting a Hidden Long image so that it won't render on scroll and there won't be any lag. But I don't feel good about it.
Can someone help me to dynamically increase the ScrollViewer content Height?
The code is here:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" Grid.RowSpan="12" Margin="10,60,10,0" >
<Image x:Name="StitchedImage" SnapsToDevicePixels="True" HorizontalAlignment="Stretch" Stretch="Fill"/>
<ScrollViewer x:Name="ImageScrollViewer" Background="Transparent" ScrollChanged="ImageScrollViewer_ScrollChanged" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" >
<Image x:Name="longImageHidden" SnapsToDevicePixels="True" Visibility="Hidden"/>
</Grid>
</ScrollViewer>
</Grid >
I think It would be really cool if I can just give a blank image specifing just height and width without any source. Is that even possible?
Yes, it is:
<Image Height="1000" />
You could also set the Height of a ScrollViewer and any other FrameworkElement derived type.

WPF: Using Grids

I created a grid and inside this grid it contains a TextBlock. When I maximize or adjust the size of the window the content of the TextBlock doesn't stay in the center of the Grid.
Tried to keep this as short as possible. :>
<Grid>
<Grid HorizontalAlignment="Left" Height="46" VerticalAlignment="Top" Width="515">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
Grids, by default, auto expand. That is, they take up as much area as they are allowed. Your outer grid will take up the entire client area of the window while the inner grid will stick to the top left of the outer grid, just as you have coded it to. If you want the inner grid to be centered, then do something like
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="46" Width="515">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
You don't even have to include the horizontal and vertical alignment as grids will automatically centre.
If you just want to centre the TextBlock ...
<Grid>
<Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Height="46" Width="515">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
The text can be centred using the TextAlignment property.
I hope this helps

How to avoid sizing grip overlap in Window

I made a WPF Window containing StatusBar with StatusBarItem and ProgressBar.
The Window has a property ResizeMode set to CanResizeWithGrip.
It shows the sizing grip properly, but it overlaps elements underneath:
How can I avoid this overlap? I can set right margin to the progress bar, but how large? I don't want to use any magic numbers or hardcoded values. It would be also nice to have this resolved purely in XAML.
You can change style for "Window" considering all wishes.
http://msdn.microsoft.com/en-us/library/aa969824(v=vs.110).aspx
or https://stackoverflow.com/a/8278917/3492412
Or can do something like this
<StatusBar VerticalAlignment="Bottom">
<StatusBarItem x:Name="statusbar" Background="Gray" HorizontalContentAlignment="Stretch">
<DockPanel>
<ResizeGrip DockPanel.Dock="Right" Visibility="Hidden" />
<ProgressBar Background="red" Height="20" Value="50" />
</DockPanel>
</StatusBarItem>
</StatusBar>

Image renders differently depending on position

I have an ItemsControl presenting a list of buttons. Each button has an image as it's content (png), but the image looks slightly different for each row.
The below image is magnified version of what I'm seeing:
Here is the xaml:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb1">hello</TextBlock>
<Button Height="{Binding ElementName=tb1, Path=ActualHeight}" Padding="0,-3,-3,-3" BorderBrush="Transparent" Background="Transparent" >
<Image Stretch="Fill" Source="stock_standard_filter.png" Margin="0">
</Image>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've had a similar issue previously and was able to solve it using SnapsToDevicePixels="True", but that solution is not working this time. I've also tried UseLayoutRounding="True" and RenderOptions.EdgeMode="Aliased"
The height of the button is bound so the image will be stretched to fill the button. Because WPF uses doubles (1/96 inch units) there is bound to be some rounding off. SnapsToDevicePixels and Layout rounding might help when you use them on the StackPanel but as long as you stretch the image it will get blurred.
My best guess is to set "Stretch to None" and experiment with SnapsToDevicePixels and Layout rounding.

WPF positioning take full height of window

Here's my layout.
<Window>
<StackPanel Orientation="Vertical">
<StackPanel HorizontalAlignment="Stretch" Height="30">
</StackPanel>
<Canvas HorizontalAlignment="Center" Width="1020">
<!--i want this to take the remaining full height of the screen-->
<Canvas x:Name="bottomInfoBar" Canvas.Bottom="0" Width="720" Height="39">
<!--I want this at the very bottom of the screen-->
</Canvas>
</Canvas>
</Window>
I want the canvas to take the full height of the window so that the 'bottomInfoBar' always remains at the very bottom of the user's screen. However if i don't specify a height for the canvas 'bottomInfoBar' appears at the very top. How do i achieve this? Please help.
Easiest way:
<Window>
<DockPanel>
<Whatever x:Name="bottomInfoBar" DockPanel.Dock="Bottom"/>
<PrimaryContent/>
</DockPanel>
</Window>
Based on your question, you really should read about WPF's layout system before you write another line of code. You'll save yourself a world of pain if you understand that before proceeding.

Resources