Windows Phone 8.1 - Building image gallery from pictures library images - c#

I'm trying to make an image gallery from pictures library images. Everything is working fine when I have a reduced number of images, but if I have more than 80 images, the phone runs out of memory. I've tried using data virtualization by defining a class which implements the ISupportIncrementalLoading interface. Then I used that class to populate my GridView, but with absolutely no luck: it still is throwing an OutOfMemoryException.
The possibility I'm thinking about is to use random access virtualization, but I haven't found any code template about it.
So,
Could you please explain me how to apply random access virtualization to my list of images?
Or
Could you please explain me how to effectively make an image gallery which retrieves its elements from the Phone's photo gallery?
My XAML code is as follows:
<GridView x:Name="photosGrid" Height="392" Width="400" ItemsSource="{Binding}" Margin="0,0,-0.333,0" SelectionMode="Multiple" Background="Black">
<GridView.ItemTemplate>
<DataTemplate>
<Image Width="90" Height="90" Margin="5" Source="{Binding}" Stretch="UniformToFill"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>

Related

Out of memory Exception on Listview with images and inkcanvas UWP

my idea is to create a listview with images, over each image I would like to insert a InkCanvas.
I tried two ways and both have problems.
First way.
I created the listview with its DataTemplate:
<DataTemplate x:Name="ListViewItemTemplate">
<Grid>
<Image></Image>
<InkCanvas></InkCanvas>
</Grid>
</DataTemplate>
<ItemsPanelTemplate x:Name="ListItemsPanelTemplate">
<VirtualizingStackPanel Orientation="Vertical">
<VirtualizingStackPanel.ChildrenTransitions>
<TransitionCollection/>
</VirtualizingStackPanel.ChildrenTransitions>
</VirtualizingStackPanel>
</ItemsPanelTemplate>
<ListView x:Name="list"
ItemTemplate="{StaticResource ListViewItemTemplate}"
ItemsPanel="{StaticResource ListItemsPanelTemplate}">
</ListView>
c#:
List<Image> pages = new List<Image>();
list.ItemsSource = pages;
In this way, the listview uses virtualization, when I write in a inkview, the stroke is copied every 5 inkview. It's not good.
If I remove the virtualization:
<ItemsPanelTemplate x:Name="ListItemsPanelTemplate">
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
It occurs the problem of the second way. Written below.
Second way:
I created a usercontrol PageFormat for the DataTemplate like this:
<UserControl>
<Grid Background="White">
<Image x:Name="image"></Image>
<InkCanvas x:Name="ink" ></InkCanvas>
</Grid>
</UserControl>
<ListView x:Name="list" ></ListView>
c#:
List<PageFormat> pages= new List<PageFormat>();
list.ItemsSource = pages;
In this way I have the following problem:like in this question
When I create more than 125 InkCanvas I have a memory problem.
I prefer the second way because I can play with the formatting of the page directly in a usercontrol, but I can not solve these problems.
I would like to solve the problem of generating InkCanvas the System.OutOfMemoryException error.
How can I solve it?
Thanks so much.
If you are 100% sure that InkCanvas is the cause of out of memory exceptions, you could do the following pseudo-system:
when a user is not editing an item, it should be persisted to disk/memory and a bitmap rendered and presented out of it.
when a user starts editing an item, de-serialize its data and realize it as an InkCanvas
i.e. use less resource-intensive types wherever it is appropriate
EDIT
Here's the solution to the fact that rendering an InkCanvas to a RenderTargetBitmap will produce a blank image:
https://mtaulty.com/2016/02/16/windows-10-uwp-inkcanvas-and-rendertargetbitmap/
(requires Win2D package)

Implement responsive Master/Detail in UWP using only one page

I would like to know if there's a way to implement a responsive Master/Detail page using only one. What I want is something exactly like the Project here:
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlMasterDetail
Except for the detail that instead of using two pages and navigating from one to another I would only use one page.
Is there a way to do it? If so, could you link me a working example?
Except for the detail that instead of using two pages and navigating from one to another I would only use one page.
After going through the project, I found it implemented a responsive master/detail experience based on the size of the screen. When the app view is sufficiently wide, the master list and detail view should appear side by side in the same app page. However, on smaller screen sizes, the two pieces of UI should appear on different pages, allowing the user to navigate between them. From my point of view, I think this is a good solution for implementing a responsive master/detail experience.
Is there a way to do it? If so, could you link me a working example?
The project already shows how to implement responsive Master/Detail in UWP using only one page, but it implements more and that makes it a little complex to understand. So I make a simple example which directly shows how to implement responsive Master/Detail in UWP using only one page.
Following is the main steps:
First, create a ListView to show master information in xaml page:
<!--Master VIEW-->
<ListView x:Name="ItemListView" Margin="0,0,0,8">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Left" Margin="10,8,0,0">
<TextBlock Text="{Binding Title}" FontSize="25" Width="400" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Second, specify the details view that shows the details item related to the selection on the master list in the same xaml page:
<!--DETAILS VIEW-->
<StackPanel Grid.Column="1" x:Name="ContentPanelDetail" Margin="10,0,0,0" DataContext="{Binding SelectedItem, ElementName=ItemListView}">
<TextBlock Text="{Binding Title}" MaxHeight="80" FontSize="30" HorizontalAlignment="Left" Margin="0" />
<TextBlock x:Name="DetailTextBlock" FontSize="35" Text="{Binding Content}" HorizontalAlignment="Left" Margin="0,18,40,0" Width="500" Height="Auto" TextWrapping="Wrap" />
</StackPanel>
Then, set the ItemsSource for the ListView in code behind:
public MainPage()
{
this.InitializeComponent();
//set the ItemsSource for the ListView
ItemDetails messageData = new ItemDetails();
ItemListView.ItemsSource = messageData.Collection;
ItemListView.SelectedIndex = 0;
}
Last but not least, put Master View and Details View into a SplitView and use VisualStateManager to make it more responsive.
Here is the simple example and the output for your reference.
To implement Master/Detail pattern on your page, you don't have to do it yourself. Instead you can use MasterDetailsView control from UWP Community Toolkit, it does a lot work for you + it is well documented.
Note: For details section of the control, do not set background to null (NoSelectionContent will be visible).

GridView out of memory with large number of ObservableCollection

I'm developing a Universal Win App and the issue is present on both platforms. I've a ObservableCollection with products, object properties are bound from xaml DataTemplate and ObservableCollection is set as ItemsSource to GridView.
private ObservableCollection<Product> productList = new ObservableCollection<Product>();
Bound products have images too.
<Image
CacheMode="BitmapCache"
Source="{Binding ImageUrl}"
Stretch="Uniform" />
GridView
<ScrollViewer
x:Name="ProductList_GridView_ParentScrollViewer"
VerticalScrollBarVisibility="Hidden"
Grid.Row="1">
<StackPanel
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Viewbox
AllowDrop="False"
ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollMode="Disabled"
Stretch="UniformToFill">
<GridView
x:Name="ProductList_GridView"
Margin="15,9.5,15,0" />
</Viewbox>
</StackPanel>
</ScrollViewer>
Also I've a kind of pagination setting which make request each time scrollable height is equal to vertical offset. And I'm adding new items to ObservableCollection by doing
foreach (var item in requestResult.products)
{
productList.Add(item);
}
this seems to work fine until i reach certain number of items. After that the app just crashes. My app's memory consumption reaches as high as 800Mb's before crashing on 2GB ram device. On 512Mb ram it crashes a lot earlier.
How can I fix the issue? Do I need to change the way I did this pagination. Or can it be fixed with small changes. I guess the problem is with Image but not sure. Isn't CacheMode="BitmapCache" supposed to fix the memory problem?
Your GridView virtualization is broken because you are wrapping it in a ScrollViewer and all items are rendered at once (and using much more memory).
If you only leave the following XAML you will have no more memory problems:
<GridView
x:Name="ProductList_GridView"
Margin="15,9.5,15,0" />

enable visualization in listbox windows phone 8

am trying to show high quality images in phone ,as my image's size is too large app shows memory warning exception. so i tried visualization .but every time the listbox loads it loads whole data
xaml code:
<ListBox x:Name="ImageStack"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
VirtualizingStackPanel.VirtualizationMode="Recycling"
>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"></VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding bimage}" />
<TextBlock Text="{Binding impath}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and i used an IList
ImageStack.ItemsSource = new VirtualSongList();
and inside virtualsonglist class
object IList.this[int index]
{
get
{
// here is where the magic happens, create/load your data on the fly.
// Debug.WriteLine("Requsted item " + index.ToString());
System.Diagnostics.Debug.WriteLine(index.ToString());
return new im { impath = "yyyyyyyyy", bimage = new BitmapImage(new Uri(#"Assets/c"+index+".png", UriKind.Relative)) };
}
set
{
throw new NotImplementedException();
}
}
can anyone suggest a efficient way to display high quality image galley in windows
Use LongListSelector that was built with Virtualization in mind.
Even in that case it might not solve your problem if you are being too aggressive with your image memory.
Since you have limited space in your WP screen try making and showing a thumbnail of your image instead at first using BitmapImage::DecodePixelHeight and BitmapImage::DecodePixelWidth instead of decoding the full thing and therefore storing the full thing in memory. You can still show the full size image inside a details page, one at a time, when the user selects to do so.
Also try experimenting with BitmapImage::CacheOption (or other caching techniques) to see how you can better keep your memory in check.

Bing Maps (Silverlight) maps - specifying canvas to be at foreground through XAML

Below is the XAML code i have for a Bing Maps Silverlight weather related implementation.
Here is what i am trying to do:
Have a bing maps with several (over 100) pushpins- on mouseover - show a contentpopup (canvas=myPopup) below. Simple enough.
Everything works fine - however, when mypopup displays on mouseover, it is not on the foreground (the other pins appear on top of the contentpopup) - hence making it not very readable.
Question:
How do i specifiy the myPopup canvas specified in XAML below to always appear in the foreground, i.e. top most of the Bing Maps silverlight control when a user views it on mouseover.
Thanks!
<Grid x:Name="LayoutRoot" Background="White">
<m:Map x:Name="GlobalMap" Mode="Road" Center="15,7" ZoomLevel="2" CredentialsProvider="{StaticResource MyCredentials}" Margin="-70,-40,-100,-72">
<m:MapLayer x:Name="myLayer">
<Canvas x:Name="myPopup" Visibility="Collapsed" Opacity="1">
<Rectangle x:Name="myPopupRectangle" Fill="White" Canvas.Left="0" Canvas.Top="0" Height="100"
Width="100" RadiusX="15" RadiusY="15"/>
<StackPanel Canvas.Left="8" Canvas.Top="8">
<TextBlock x:Name="myPopupTexts" FontSize="5" Width="100">
</TextBlock>
</StackPanel>
</Canvas>
</m:MapLayer>
</m:Map>
</Grid>
Try adding Canvas.ZIndex to the MapLayer element, give it a large value like 200 or add your push pins to another MapLayer (rather than adding the pins directly to the map) that appears ahead of this popup layer in document order.
I did something similar to this, but took a different approach. What I did was create a custom pushpin template and create a PopUp within the template.
When the user hovers over the pushpin, the popup is displayed. Using the PopUp will solve your problem, since the control will automatically position it on top of everything. Try wrapping the Canvas in a PopPup and see if that works.
hth

Categories

Resources