horizontal listbox that could be infinite circle scrolling - windows-phone-7

I would like to make a horizontal listbox that could be infinite scrolling (looping listbox/scrollviewer, or circular listbox/scrollviewer), means that when I scroll to its end, its would scroll over from beginning.
I have tried to make the listbox horizontal, but it wouldn't scroll so I put it inside a scrollviewer to have it scroll horizontally. However it's not the listbox that scroll and I need them somehow to scroll over from beginning.
This is what I have so far:
private void DoWebClient()
{
var webClient = new WebClient();
webClient.OpenReadAsync(new Uri("http://music.mobion.vn/api/v1/music/userstop?devid="));
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
using (var reader = new StreamReader(e.Result))
{
string s = reader.ReadToEnd();
Stream str = e.Result;
str.Position = 0;
XDocument xdoc = XDocument.Load(str);
var data = from query in xdoc.Descendants("user")
select new mobion
{
avlink = (string)query.Element("user_info").Element("avlink"),
nickname = (string)query.Element("user_info").Element("nickname"),
track = (string)query.Element("track"),
artist = (string)query.Element("artist"),
};
listBox.ItemsSource = data;
}
}
Mainpage.xaml
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="DataTemplate1">
<Grid/>
</DataTemplate>
<Storyboard x:Name="Storyboard1" RepeatBehavior="forever" Completed="Storyboard1_Completed">
<DoubleAnimation Duration="0:0:25" To="-2400" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="imagesScrollview" d:IsOptimized="True"/>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto" Margin="8,563,-2400,2" Width="auto" x:Name="imagesScrollview" Opacity="1" Background="#FF3ED216" Grid.Row="1" RenderTransformOrigin="0.5,0.5">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<im:ControlStoryboardAction Storyboard="{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ScrollViewer.RenderTransform>
<CompositeTransform/>
</ScrollViewer.RenderTransform>
<ListBox x:Name="listBox" Width="Auto" Height="Auto" Background="#FF3ED216" ManipulationCompleted="listBox_ManipulationCompleted">
<ListBox.RenderTransform>
<CompositeTransform/>
</ListBox.RenderTransform>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.RenderTransform>
<TranslateTransform X="0" />
</StackPanel.RenderTransform>
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="15,0">
<Image Name="imageAV" Source="{Binding Path=avlink}" Height="80" Width="80" Stretch="UniformToFill" MouseLeftButtonUp="imageAV_MouseLeftButtonUp" ImageFailed="imageAV_ImageFailed" />
<StackPanel Orientation="Vertical" Margin="10,0,0,0" MouseLeftButtonUp="StackPanel_MouseLeftButtonUp">
<TextBlock Name="indexTextBlock" Text="{Binding num}" />
<TextBlock Text="{Binding nickname}"/>
<TextBlock Text="{Binding track}" FontWeight="Bold" />
<TextBlock Text="{Binding artist}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>

To make a listbox scroll horizontally you need to set the ScrollBar Visibility properties of the internal ScrollViewer.
Like this:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled" >
The Toolkit includes a LoopingSelector class that you could based your own control implementation on. There's an example of creating such a control at http://babaandthepigman.wordpress.com/2010/09/22/wp7-looping-selector/ (although it is for a vertical list)

Not sure if that helps, but the standard approach to infinite scrolling is to put at least one screenful of duplicate items from the beginning of the list at the end, and upon reaching the end, transparently skip (1-step scroll) to the beginning or a fixed short offset from it (and vice versa) so that it looks the same but the user looks at the items from the beginning of the list, not their duplicates from the end.

Related

MenuFlyout for Items in GridView in Windows 8.1 HubApp

I have Windows 8.1 Hub App that will eventually be released for tablets. I want to add MenuFlyout to GridView. So if I right click or hold then flyout will display. I've gone through several videos, tutorials etc. but none of them relates to GridView. Only for ListView on WindowsPhone. So none of them show how I should approach.
Is it possible? How I should deal with it?
HubSection
This is how my Hubsection with GridView looks like.
<HubSection x:Name="CalcButtons" x:Uid="calculator" Header="{Binding Res.calc2Header, Source={StaticResource SharedStrings}}">
<DataTemplate>
<GridView
ItemsSource="{Binding}"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
ItemTemplate="{StaticResource StandardCalcButton}"
SelectionMode="None"
IsItemClickEnabled="True" Margin="0,0,0,0" ItemClick="GridView_ItemClick">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</DataTemplate>
</HubSection>
StandardCalcButton
I've created MenuFlayout as resource in App.xaml and attached it to GridViewItem DataTemplate. So it looks like this.
<MenuFlyout x:Key="CalcFlyout">
<MenuFlyoutItem Text="Test1"/>
<MenuFlyoutItem Text="Test2"/>
</MenuFlyout>
<DataTemplate x:Key="StandardCalcButton" >
<Grid Height="180" Width="180" Margin="5,5,5,5" FlyoutBase.AttachedFlyout="{StaticResource CalcFlyout}" >
<Border Height="180" Background="{StaticResource AppYellow}">
<StackPanel Grid.Row="1" Margin="0,0,0,0">
<Image Source="{Binding ImagePath}" AutomationProperties.Name="{Binding Title}" Height="130" Width="180"/>
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" TextLineBounds="Tight" TextAlignment="Center"/>
<TextBlock Text="{Binding Subtitle}" Style="{StaticResource BodyTextBlockStyle}" TextWrapping="NoWrap" TextLineBounds="Tight" LineStackingStrategy="BlockLineHeight" TextTrimming="CharacterEllipsis" TextAlignment="Center" />
</StackPanel>
</Border>
</Grid>
</DataTemplate>
This is how I want to make Flyout to open in GridView_ItemClicked
private void GridView_ItemClick(object sender, ItemClickEventArgs e){
FrameworkElement senderElement = e.ClickedItem as FrameworkElement;
if (senderElement == null)
{
Debug.WriteLine("null");
return;
} else
{
FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);
flyoutBase.ShowAt(senderElement);
}
}
''ClickedItem'' is object which I deliver in ''GridView.DataContext'' so there is no way that it will be castable to FrameworkElement.
Now I'm stuck. I'll be thankful for any guidance.
You can try the following:
private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
var gridViewItemsControl = sender as ItemsControl;
var clickedItemContainer = gridViewItemsControl.ContainerFromItem(e.ClickedItem);
Debug.WriteLine(clickedItemContainer);
var clickedGridViewItem = clickedItemContainer as GridViewItem;
var clickedItemGrid = clickedGridViewItem.ContentTemplateRoot as Grid;
FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(clickedItemGrid);
flyoutBase.ShowAt(clickedItemGrid);
}
Hope i helps! :)

Getting information from child element of stackpanel within listbox

I know there should be a simple solution to this question but I just cant seem to figure it out here is what my code looks like:
<ListBox HorizontalAlignment="Left"
x:Name="locationsNB"
VerticalAlignment="Top"
Height="563"
Width="455"
SelectionChanged="locationsNB_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Margin="18,0,0,0"
x:Name="placeDetails">
<Image Source="{Binding icon}"
Height="40"
Width="40"
VerticalAlignment="Top"
Margin="0,10,8,0" />
<StackPanel Width="350">
<TextBlock Text="{Binding name}"
FontSize="35"
Foreground="#399B81"
TextWrapping="Wrap" />
<TextBlock Text="{Binding vicinity}"
FontSize="20"
Foreground="#888888"
TextWrapping="Wrap" />
<TextBlock x:Name="reference"
Text="{Binding reference}"
Visibility="Collapsed" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want to get the stackpanel->reference text (Text="{Binding reference}") of the selected item I dont know what my C# should look like but any help will be greatly appreciated.
If the ItemsSource of your ListBox is bound to a collection of items then you can use the SelectedItem property of the ListBox
private void locationsNB_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listbox = (ListBox)sender;
var myObject = listbox.SelectedItem as MyCustomObject;
if (myObject == null) return;
// perform your custom logic with this item
}

Getting Data from a Data Bound Map View Item's Context Menu

I'm writing a Windows Phone application that shows a number of locations on a map. These positions have phone numbers, twitter accounts and websites associated with them.
What I want to do is add a context menu to the items that allows the user to open the websites, view twitter or call the phone number. However, with a MapItemsControl their is no easy way to get the current item.
I am looking for some way to do this in as painless a way as possible.
Some code:
<mi:MapItemsControl x:Name="mapPins" ItemsSource="{Binding Pushpins}">
<mi:MapItemsControl.ItemTemplate>
<DataTemplate>
<mi:Pushpin Location="{Binding Location}">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsEnabled="{Binding ShowContext}" >
<TextBlock Opacity="{Binding Opacity, ElementName=image}" Text="Show Menu"/>
<TextBlock Opacity="{Binding Opacity, ElementName=image1}" Text="Open Webpage" Tap="EOpenWeb" />
<StackPanel Opacity="{Binding Opacity, ElementName=image2}" Orientation="Horizontal" Tap="ECallPhone">
<TextBlock Text="Call "/>
<TextBlock Text="{Binding Contact.FormattedPhone}"/>
</StackPanel>
<TextBlock Opacity="{Binding Opacity, ElementName=image3}" Text="On Twitter" Tap="EOpenTwitter" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Foreground="{Binding Foreground}" Text="{Binding Name}" d:LayoutOverrides="HorizontalAlignment"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,-6" Visibility="{Binding ShowGlyphs}">
<TextBlock TextWrapping="Wrap" Text="{Binding HereNow}" Visibility="{Binding ShowHere}" VerticalAlignment="Center" FontSize="{StaticResource PhoneFontSizeMediumLarge}" HorizontalAlignment="Left" Height="36" Width="48" TextAlignment="Center"/>
<Image x:Name="image" Height="48" Opacity="{Binding HasMenu}" Source="locationGlyphs/appbar.book.open.png" Stretch="Fill"/>
<Image x:Name="image1" Height="48" Opacity="{Binding HasWeb}" Source="locationGlyphs/appbar.link.png" Stretch="Fill" Width="48"/>
<Image x:Name="image2" Height="48" Opacity="{Binding HasPhone}" Source="locationGlyphs/appbar.phone.png" Stretch="Fill" Width="48"/>
<Image x:Name="image3" Height="48" Opacity="{Binding HasTwitter}" Source="locationGlyphs/appbar.twitter.bird.png" Stretch="Fill" Width="48"/>
</StackPanel>
</StackPanel>
</mi:Pushpin>
</DataTemplate>
</mi:MapItemsControl.ItemTemplate>
</mi:MapItemsControl>
That details how the objects are drawn to the map. The Pushpins list is just an Observable Collection of my data.
If this was a ListBox I could simply use the SelectedItem or similar to resolve this, but that doesn't seem an option for MapItemsControl. Has anyone managed to do this successfully? How?
You need to somehow react to the tap on the pushpin. You have a contextmenu and you clearly need to go that way at the moment. needs to have a tap event handler attached:
<mi:Pushpin
Location="{Binding Location}" Tap="Pushpin_Tap">
Pushpin_Tap event handler needs to be managed similar to this:
private void Pushpin_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var _ppmodel = sender as Pushpin;
ContextMenu contextMenu =
ContextMenuService.GetContextMenu(_ppmodel);
contextMenu.DataContext = _viewModel.Pushpins.Where
(c => (c.Location
== _ppmodel.Location)).FirstOrDefault();
// this way you can find which pushpin/position was tapped by finding the
// one which has the same location in your Pushpins observable collection
if (contextMenu.Parent == null)
{
contextMenu.IsOpen = true;
}
}
I wrote about showing a context menu on pushpin tap on my blog, so if you wish you can go and read the whole story there.

ProgressBar on Windows Phone 7 is not showing

I am trying to show a ProgressBar in my Windows Phone 7 app when the app is fetching data.
Here is my XAML:
<!--Panorama item one-->
<controls:PanoramaItem Header="headlines">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="220" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Button Name="refresh" Margin="320,-630,0,0" Grid.ColumnSpan="2" Height="75" Width="75" BorderThickness="0" Click="refresh_Click">
<Button.Foreground>
<ImageBrush ImageSource="/DataCollector.Tone;component/Resources/refresh-pressed.png" />
</Button.Foreground>
<Button.Background>
<ImageBrush ImageSource="/DataCollector.Tone;component/Resources/refresh.png" />
</Button.Background>
</Button>
<TextBlock Text="from heraldsun" Margin="12,-30,0,0" Style="{StaticResource PhoneTextSubtleStyle}" Grid.ColumnSpan="2"></TextBlock>
<ProgressBar
Margin="0,-40,0,0"
x:Name="progressBar"
IsIndeterminate="true"
Visibility="Visible" Grid.ColumnSpan="2" />
<ListBox Name="headlines" Margin="0,10,-12,0" ItemsSource="{Binding Tones}" Visibility="Collapsed" Grid.ColumnSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,17,0,17">
<!--Replace rectangle with image-->
<Image Source="{Binding ImageUrl}" Height="75" Width="100" Margin="12,10,9,0" VerticalAlignment="Top" />
<!--<Rectangle Height="100" Width="100" Fill="#FFE5001b" Margin="12,0,9,0"/>-->
<StackPanel Width="311">
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!--Double line list with image placeholder and text wrapping-->
</Grid>
</controls:PanoramaItem>
Here is the back end code:
// Load data for the ViewModel Items
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
progressBar.Visibility = Visibility.Collapsed;
headlines.Visibility = Visibility.Visible;
}
}
I recommend using the PerformanceProgressBar from the toolkit.
It runs on the compositor thread, so it won't block with UI things.
In following code:
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
progressBar.Visibility = Visibility.Collapsed;
headlines.Visibility = Visibility.Visible;
}
If App.ViewModel.LoadData() is a synchronous method, thant may be keeping your UI from updating.
Try putting entire MainPage_Loaded code into a seperate method and call it asynchronously.
If I'm reading your most recent comment correctly, the problem you have now is that the value of the visible is initialy true, because the data is loading, and then the binding never occurs again when the data is loaded. I would recommend hooking up to an event (and making it on the data model if need be)
App.ViewModel.OnDataLoaded += (s, e) => performanceProgressBar.Visibility = Visibility.Hidden

Reloading listbox in WP7

I am using List to bind a listbox which is as follows:
<ListBox x:Name="ContentPanel" SelectionChanged="onSelectionChanged" Background="LightGray" Grid.Row="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Name="{Binding title}" Height="165" Margin="25,5,25,0" Width="430">
<Border BorderThickness="1" Height="165" BorderBrush="Gray">
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu IsZoomEnabled="False">
<toolkit:MenuItem Name="Delete" Header="Delete Message" Click="DeleteMessage_Click" >
</toolkit:MenuItem>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<StackPanel Orientation="Vertical">
<StackPanel>
<TextBlock Text="{Binding title}" Margin="5,0,0,0" FontSize="25" Foreground="Black"/>
<TextBlock Text="{Binding msgFrom}" Padding="5" TextWrapping="Wrap" Foreground="Gray" FontSize="20"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,13,0,0" FontSize="24" Foreground="WhiteSmoke" Text="{Binding msgReceivedOn}"/>
<toolkit:ToggleSwitch Margin="170,10,0,0" IsChecked="{Binding msgStatus}" Unchecked="UnChecked" Background="LightBlue" Checked="Checked"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
At first data is successfully loaded. But when I use the Contextmenu to remove the item and reload the listbox.. it fires an exception. Code to handle the context menu click is:
private void DeleteMessage_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
Message message = (Message)item.DataContext;
MessageBoxResult result = MessageBox.Show("Are you sure to delete the message??", "Confirmation", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.Cancel)
return;
else
{
ContentPanel.Items.Remove(message);
lstMessage.Remove(message);
}
ContentPanel.ItemSource = lstMessage;
}
But it this code is not working. So any suggestions?
You don't need each time to bind collection to a list. Also, when you remove an item from your collection, it should disappear also in the list (if binding setup properly). I think you have not ObservableCollection, so you need manage items manually. Please, consider to use ObservableCollection.
Your code should looks like:
lstMessage.Remove(message); //it must raises CollectionChanged event automatically
And this lines is unnecessary:
ContentPanel.Items.Remove(message);
ContentPanel.ItemSource = lstMessage;

Resources