Out of memory - 15+ PivotItems in PivotControl - windows-phone-8

I have a pivot control that its ItemsSource is databound to a collection of items.
The collection can be up to 50 items, so it means that it can be up to 50 PivotItems.
Each PivotItem contains Image control and some text controls.
After swiping between the pivot pages (about 15), when pressing the back button, the app crashs with "Out of Memory" exception.
Ofcourse the problem is in the PivotItems that takes all the memory each time I swipe to a new one.
I know the guildlines not recommend to use pivot with more than 6-7 items, but I really need it that way.
I saw some answer on the web that advices to use ContentControl with Content binded to my item layout as Resource.. but I find it hard to Implement.
Any more suggestions how to achieve the desirable result (no memory overflow)?
Thanks!
Edit:
I tried to manipulate the items by taking only 3, the current, the next and the previous.
But the behavior of the pivot is not good.. How should I increment/decrement the Pivot.SelectedIndex?
private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
{
if (e.Direction.ToString() == "Horizontal") //Left or right
{
var itemVM = this.DataContext as ItemViewModel;
int i = pivot.SelectedIndex;
ObservableCollection<Item> items = new ObservableCollection<Item>();
var currentItemIndex = itemVM.CurrentReader.Reader.Items.IndexOf(itemVM.SelectedItem);
if (e.HorizontalVelocity > 0) //Right
{
currentItemIndex++;
}
else //Left
{
currentItemIndex--;
}
if (itemVM.AllItems.Count >= 3)
{
if (currentItemIndex == 0) // in case we are in the first item m in the AllItems collection.
{
items.Add(itemVM.AllItems[itemVM.AllItems.Count - 1]);
items.Add(itemVM.AllItems[currentItemIndex]);
items.Add(itemVM.AllItems[currentItemIndex + 1]);
}
else if (currentItemIndex == itemVM.AllItems.Count - 1) // in case we are in the last item in the AllItems collection.
{
items.Add(itemVM.AllItems[currentItemIndex - 1]);
items.Add(itemVM.AllItems[currentItemIndex]);
items.Add(itemVM.AllItems[0]);
}
else
{
items.Add(itemVM.AllItems[currentItemIndex - 1]);
items.Add(itemVM.AllItems[currentItemIndex]);
items.Add(itemVM.AllItems[currentItemIndex + 1]);
}
}
else // in case we have only 3 items, no manpulation needed.
{
items = itemVM.AllItems;
}
itemVM.CurrentItemsCollection = items; // only 3 items
}
}

Related

Guessing Number Game Program not Functioning Correctly

in my program, the user sets a range of numbers for the computer to guess. The user then has to guess which number the computer chose with a limit of guesses starting at 5. There are several problems in my functioning program in which I do not understand how to fix. These errors include:
-The number of guesses left always remains at 0. It won't start at 5 and decrease by 1 each time I click the btnCheck button.
-Whenever I click the btnCheck button for a new guessing number, the statement if you've guessed too high or too low remains the same.
-When I press btnNewGame, the values I insert in my low value and my high value text inputs will not be cleared.
-How can the computer generate a random whole number based on what I set as the number range?
Revising my code down below will be much appreciated.
// This line makes the button, btnCheckGuess wait for a mouse click
// When the button is clicked, the checkGuess function is called
btnCheckGuess.addEventListener(MouseEvent.CLICK, checkGuess);
// This line makes the button, btnNewGame wait for a mouse click
// When the button is clicked, the newGame function is called
btnNewGame.addEventListener(MouseEvent.CLICK, newGame);
// Declare Global Variables
var computerGuess:String; // the computer's guess
var Statement:String; // Statement based on your outcome
// This is the checkGuess function
// e:MouseEvent is the click event experienced by the button
// void indicates that the function does not return a value
function checkGuess(e:MouseEvent):void
{
var LowValue:Number; // the user's low value
var HighValue:Number; // the user's high value
var UserGuess:Number; // the user's guess
var CorrectGuess:int; // the correct number
var FirstGuess:String; //the user's guess
// get the user's range and guess
LowValue = Number(txtinLow.text);
HighValue = Number(txtinHigh.text);
UserGuess = Number(txtinGuess.text);
// determine the number of the user
GuessesLeft = checkCorrectGuess(FirstGuess);
lblNumber.text = GuessesLeft.toString();
lblStatement.text = "You have guessed " + Statement.toString() + "\r";
}
// This is function checkColoursCorrect
// g1– the user's guess
function checkCorrectGuess(g1:String):int
{
var GuessesLeft:int = 5; // How many guesses are left
if (g1 != computerGuess)
{
GuessesLeft - 1;
}
else
{
GuessesLeft = 0;
}
return GuessesLeft;
}
// This is the newGame function
// e:MouseEvent is the click event experienced by the button
// void indicates that the function does not return a value
function newGame(e:MouseEvent):void
{
var Guess1:int; // computer's guess in numbers
var UserGuess1:int; // user's guess in numbers
Guess1 = randomWholeNumber(100,1); //It is not (100,1). How do I change this to the range the user put?
UserGuess1 = randomWholeNumber(100,1); //It is not (100,1). How do I change this to the range the user put?
if (Guess1 > UserGuess1) {
Statement = "TOO HIGH";
} else if (Guess1 < UserGuess1) {
Statement = "TOO LOW";
} else if (Guess1 == UserGuess1) {
Statement = "CORRECTLY";
}
txtinGuess.text = "";
lblStatement.text = "";
}
// This is function randomWholeNumber
// highNumber – the maximum value desired
// lowNumber – the minimum value desired
// returns – a random whole number from highNumber to lowNumber inclusive
function randomWholeNumber(highNumber:int,lowNumber:int):int //How do I make a whole random number based on the range the user made?
{
return Math.floor((highNumber - lowNumber + 1) * Math.random() + lowNumber);
}
To answer your questions...
You've declared GuessesLeft inside checkCorrectGuess() which means its a local variable that's being redefined every time you call the function. Futhermore, because you're passing in var FirstGuess:String; (an uninitialized, non-referenced string variable), (g1 != computerGuess) is returning false, and the answer is always 0.
GuessesLeft - 1; is not saving the result back to the variable. You need to use an assignment operator such as GuessesLeft = GuessesLeft - 1 or simply type GuessesLeft-- if all you want is to decrement. You could also write GuessesLeft -= 1 which subtracts the right from the left, and assigns the value to the variable on the left. See AS3 Operators...
You've already assigned values to these TextFields earlier; simply repeat the process inside of newGame() with a txtinLow.text = "" (same with high)
Use your variables. You defined them earlier in checkGuess() as UserGuess, LowValue, and HighValue
Be mindful that you only need to split out functionality into separate functions if that piece of code is likely to be called elsewhere. Otherwise, every function on the stack incurs more memory and performance hits. checkCorrectGuess() falls into that category and is therefore unnecessary.
Also, you are printing your feedback to the user in the newGame() function instead of checkGuess(). It seemed like an oversight.
btnCheckGuess.addEventListener(MouseEvent.CLICK, checkGuess);
btnNewGame.addEventListener(MouseEvent.CLICK, newGame);
// Global Variables
var computerGuess:int;
var remainingGuesses:int;
newGame();
function newGame(e:MouseEvent):void {
// Reset our guess limit
remainingGuesses = 5;
// Generate a new number
computerGuess = random(int(txtinLow.text), int(txtinHigh.text));
// Reset our readouts.
txtinGuess.text = "";
lblStatement.text = "";
}
function checkGuess(e:MouseEvent):void {
var guess:int = int(txtinGuess.text);
var msg:String;
if (guess == computerGuess) { // Win
remainingGuesses = 0; // Zero our count
msg = "CORRECT";
} else { // Missed
remainingGuesses--; // Decrement our count
if (guess > computerGuess) {
msg = "TOO HIGH";
} else if (guess < computerGuess) {
msg = "TOO LOW";
}
}
lblNumber.text = remainingGuesses.toString();
lblStatement.text = "You have guessed " + msg;
}
function random(low:int, high:int):int {
return Math.floor((high - low + 1) * Math.random() + low);
}

Get first visible item in a GridView/ListView

I'm showing a set of pictures in a page. I use a GridView to show the pictures. However, when the user resizes the screen to make it narrow, I switch to a ListView.
The problem now is synchronizing the scroll position for the two lists. My approach to the solution is,
1. Get the first visible item of the first list.
2. Scroll the second list to that item using ScrollIntoView
However I'm unable to see any property in GridView/ListView that gives me the first information. Any ideas?
Also any other ways of doing this are appreciated.
That seems to be just about the way I would first try to do it. You can use the ItemsPanelRoot property of the GridView/ListView and get the Children of the panel, then use TransformToVisual().TransformPoint() relative to the list control on each child to find the first one that is visible.
The one gotcha I can think of is when ScrollIntoView() would scroll the item that was first in view port in one list to show as last in view in the other one. Maybe you could get the ScrollViewer from the template of the list control (e.g. by using VisualTreeHelper) and scroll to the beginning of the list first?
The most simple way to do it all might be to just scroll to the same relative offset in the list coming into view as the one going out. It might not be very precise, but it could work.
You could even do a nice animated transition of elements in one list into the elements in the other one.
*Update
I asked around and it seems like I forgot that the default panels in GridView and ListView - the ItemsWrapGrid and ItemsStackPanel contain a FirstVisibleIndex property that could be used to get the object and then call ScrollIntoView() on the list control, which in turns takes a ScrollIntoViewAlignment enum you can use to say you want the scrolled-to-item to be the first visible (aligned to the leading edge).
*Update 2
For ListViewBase - you can also use the ListViewPersistenceHelper to get and set relative offsets.
This upcoming update to WinRT XAML Toolkit might be helpful as it would allow you to simply call: gridView.SynchronizeScrollOffset(listView); or vice versa.
public static class ItemsControlExtensions
{
public static ScrollViewer GetScrollViewer(this ItemsControl itemsControl)
{
return itemsControl.GetFirstDescendantOfType<ScrollViewer>();
}
public static int GetFirstVisibleIndex(this ItemsControl itemsControl)
{
// First checking if no items source or an empty one is used
if (itemsControl.ItemsSource == null)
{
return -1;
}
var enumItemsSource = itemsControl.ItemsSource as IEnumerable;
if (enumItemsSource != null && !enumItemsSource.GetEnumerator().MoveNext())
{
return -1;
}
// Check if a modern panel is used as an items panel
var sourcePanel = itemsControl.ItemsPanelRoot;
if (sourcePanel == null)
{
throw new InvalidOperationException("Can't get first visible index from an ItemsControl with no ItemsPanel.");
}
var isp = sourcePanel as ItemsStackPanel;
if (isp != null)
{
return isp.FirstVisibleIndex;
}
var iwg = sourcePanel as ItemsWrapGrid;
if (iwg != null)
{
return iwg.FirstVisibleIndex;
}
// Check containers for first one in view
if (sourcePanel.Children.Count == 0)
{
return -1;
}
if (itemsControl.ActualWidth == 0)
{
throw new InvalidOperationException("Can't get first visible index from an ItemsControl that is not loaded or has zero size.");
}
for (int i = 0; i < sourcePanel.Children.Count; i++)
{
var container = (FrameworkElement)sourcePanel.Children[i];
var bounds = container.TransformToVisual(itemsControl).TransformBounds(new Rect(0, 0, container.ActualWidth, container.ActualHeight));
if (bounds.Left < itemsControl.ActualWidth &&
bounds.Top < itemsControl.ActualHeight &&
bounds.Right > 0 &&
bounds.Bottom > 0)
{
return itemsControl.IndexFromContainer(container);
}
}
throw new InvalidOperationException();
}
public static void SynchronizeScrollOffset(this ItemsControl targetItemsControl, ItemsControl sourceItemsControl, bool throwOnFail = false)
{
var firstVisibleIndex = sourceItemsControl.GetFirstVisibleIndex();
if (firstVisibleIndex == -1)
{
if (throwOnFail)
{
throw new InvalidOperationException();
}
return;
}
var targetListBox = targetItemsControl as ListBox;
if (targetListBox != null)
{
targetListBox.ScrollIntoView(sourceItemsControl.IndexFromContainer(sourceItemsControl.ContainerFromIndex(firstVisibleIndex)));
return;
}
var targetListViewBase = targetItemsControl as ListViewBase;
if (targetListViewBase != null)
{
targetListViewBase.ScrollIntoView(sourceItemsControl.IndexFromContainer(sourceItemsControl.ContainerFromIndex(firstVisibleIndex)), ScrollIntoViewAlignment.Leading);
return;
}
var scrollViewer = targetItemsControl.GetScrollViewer();
if (scrollViewer != null)
{
var container = (FrameworkElement) targetItemsControl.ContainerFromIndex(firstVisibleIndex);
var position = container.TransformToVisual(scrollViewer).TransformPoint(new Point());
scrollViewer.ChangeView(scrollViewer.HorizontalOffset + position.X, scrollViewer.VerticalOffset + position.Y, null);
}
}
}

How do you create an if statement to check if many objects style == dispaly:none?

I'm making a memory-match game in which you flip two cards over in order to get them to match.
I'm doing it with simple if statements as shown below:
if(click == 2) //denotes two cards being clicked
{
if(flippedArray[1].src === flippedArray[0].src) // if click 1 == click 2 then refer to function 'delayMatch' which sets click 1 and 2 cards to not be displayed
{
window.setTimeout(function() { delayMatch() }, 500);
console.log("EQUAL");
score = +25000;
}
else
{
window.setTimeout(function() { delayNoMatch() }, 500); // if click 1 != click 2 then display card.png
console.log("NOT EQUAL");
score = -1999;
}
function delayMatch() //function for matching pairs
{
flippedArray[0].style = "display:none;";
flippedArray[1].style = "display:none;";
}
function delayNoMatch() //function for non-matching pairs
{
flippedArray[0].src = "card.png";
flippedArray[1].src = "card.png";
}
click = 0; // when clicked two cards set click back to zero
}
As you can see if two cards match they're set to display:none. What I'm trying to do is link to an "end game" html page once all 36 divs are set to display: none or I guess once the function delayMatch() has been called 18 times.
I'm completely at a loss as how I can do this.
my goal is something like this:
flippedArray[0] and flippedArray[1] is just a temporary array to check if the two cards currently in play are a match or not.
I was thinking something like:
endGameCounter =0;
endGameCounter++; //in the matching if-statement
then if(endGameCounter == 18)
{
location.href='link here'
}
You can use one variable for count inside the page.
If you are doing it in JSP, JSTL can help you here.
use to set a variable and just check the value time to time.
c:set var="COUNT" value="SOMETHING"/>
Try
function GameIsOver(){
for (var i = 0; i < allCards.length; i++) {
if(allCards[i].style.display === 'none')return false;
}
return true;
}

Windows Phone MultiSelect ListBox selected items

For about three hours, I've been trying to get selected indexes of a multiselect listbox. I tried variety of solutions but they don't work. The final thing I've found is the following;
for (int i = 0; i < this.myListBox.Items.Count; i++)
{
ListBoxItem currentItem = this.myListBox.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
if (currentItem != null && currentItem.IsSelected)
{
ApplicationManager.Instance.getContactManager().addToIndexes(i);
}
}
This seems to work but when I scroll-down in the list for example, listboxitem of previously selected items returns null. How can I accomplish this task?
As per my understanding of your question you require selected index...
so you have to use List box tap event and than find selected index
for example
private void mylistbox_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
{
List<ClsReportId> lstrptId = new List<ClsReportId>();
ListBox lst = (ListBox)sender;
int i = lst.SelectedIndex;
if (lst.SelectedValue == null)
{
}
else
{
ClsGetSubmittedReport cls = (ClsGetSubmittedReport)lst.SelectedValue;
reportId = cls.ReportId1.ToString();
}
}
Hope it will help you
Thanks

Show limited no. of page links in pagination

I want to display a limited no. of page links, say 5 out of 10 links, and was wondering is there any known or tried and tested method to achieve this.
so lets say user can right now see following links
previous, 1(selected), 2, 3, 4, 5... next
user clicks on, say 4, now he sees
previous... 3, 4(selected), 5, 6, 7...next
now he clicks on 7
previous... 6, 7(selected), 8, 9, 10...next
Now I believe this to be something very common in pagination programming. So is there any known algo to do this. I am feeling too lazy to cookup my own!
Edit:- This needs to be achieved on the server side. I am working on C#, however you can pitch in algo in any language.
The problem with some of the answers, especially with Tyrone's is that it only updates the navigation when the remainder is 0, if you want it to update on every click then the following is much better:
var start,
end,
pagesCutOff = 5,
ceiling = Math.ceil(pagesCutOff / 2),
floor = Math.floor(pagesCutOff / 2);
if(numPages < pagesCutOff) {
start = 0;
end = numPages;
} else if(currentPage >= 1 && currentPage <= ceiling) {
start = 0;
end = pagesCutOff;
} else if((currentPage + floor) >= numPages) {
start = (numPages - pagesCutOff);
end = numPages;
} else {
start = (currentPage - ceiling);
end = (currentPage + floor);
}
Obviously you send through the currentPage and numPages yourself to the function, this will keep the current page centered in the pagination list, the number of buttons shown should be an odd number so that the selected page can be "in the middle" of the list.
You can then do the following loop:
for (var i = start; i < end; i++) {
//Your code here
}
If you want to add a next and previous button to this then simply do something like:
if(currentPage !== 1) {
$('< Previous').appendTo(navElement);
}
Where navElement is a jQuery object of where you want to append the list to like: $('#pagination-nav');
Hope this helps someone!
Cheers
Tested this and it works even though it could be a little more graceful. I am using C# here, but the logic for any language should be the same. If you come up with a better solution please post. If you have any questions please post to. I have commented the code to help better explain what is going on.
//Get the current page we are on
int start = currentPage;
int end = currentPage;
//If the page cannot be devised by 5 enter the loop
if ((start % 5 != 0) && (end % 5 != 0))
{
//Get the next nearest page that is divisible by 5
while ((end % 5) != 0)
{
end++;
}
//Get the previous nearest page that is divisible by 5
while ((start % 5) != 0)
{
start--;
}
}
//The page is divisible by 5 so get the next 5 pages in the pagination
else
{
end += 5;
}
//We are on the first page
if (start == 0)
{
start++;
end++;
}
//We are on the last page
if (end == lastpage)
{
end = lastpage;
}
//Post your pagination links below
for (int i = start; i < end; i++)
{
//Your code here
}
The problem with some of the answers, especially with Tyrone's is that it only updates the navigation when the remainder is 0, if you want it to update on every click then the following is much better:
//Get the current page we are on
int start = currentPage;
int end = currentPage;
//If the page cannot be devised by 5 enter the loop
if ((start % 5 != 0) && (end % 5 != 0))
{
//Get the next nearest page that is divisible by 5
while ((end % 5) != 0)
{
end++;
}
//Get the previous nearest page that is divisible by 5
while ((start % 5) != 0)
{
start--;
}
}
//The page is divisible by 5 so get the next 5 pages in the pagination
else
{
end += 5;
}
//We are on the first page
if (start == 0)
{
start++;
end++;
}
//We are on the last page
if (end == lastpage)
{
end = lastpage;
}
//Post your pagination links below
for (int i = start; i < end; i++)
{
//Your code here
}
You can't do this with just HTML. You'll have to use either PHP or javascript (or some other scripting language) to generate the links.
I had to limit no of page links on the pager to 3 on small (mobile) devices. I used following code to achieve it.
//If it is full page, pager
//Assume all page links are visible
//Get the actual pages links count
var noOfPages = $('ul.pagination li.pager__item').not('.pager__item--first, .pager__item--previous,.pager__item--last, .pager__item--next').length;
var pages = [];
if (noOfPages > 3) {
var activePage = 0;
var index = 0;
$('ul.pagination li.pager__item').not('.pager__item--first, .pager__item--previous,.pager__item--last, .pager__item--next').each(function() {
//Get the active page no.
if ($(this).hasClass('current')) {
activePage = index;
}
//Hide page link
$(this).css('display', 'none');
pages.push($(this));
index++;
});
var start;
var end;
//We are at page 1 (i.e page=0)
if(activePage == 0) {
start = 0;
end = 2;
}
// Wer are at last page
else if(activePage == noOfPages - 1) {
start = activePage - 2;
end = activePage;
}
else {
start = activePage - 1;
end = activePage + 1;
}
for (var i = start; i <= end; i++) {
pages[i].css('display', 'inline-block');
}
}