Handling tap on Pushpin in a fixed Map - windows-phone-7

I have a Map control showing a few Pushpins. I do not want the user to navigate in the map so I disable it. But I do want the user to be able to tap on a Pushpin (and in the event I navigate to a detail page).
However when the Map.IsEnabled is false, the Pushpins don't seem to receive any gestures either. I've also tried using IsHitTestVisible, but with no luck.
Some code showing what I'm trying to do. Does anyone have any ideas?
<maps:Map Name="Map"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ScaleVisibility="Collapsed" ZoomBarVisibility="Collapsed"
IsEnabled="False">
<maps:MapItemsControl ItemsSource="{Binding TheCollection}">
<maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<maps:Pushpin Name="Pin" Location="{Binding Coordinate}" Content="{Binding Ix}">
<maps:Pushpin.Background>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</maps:Pushpin.Background>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="PinTap" />
</toolkit:GestureService.GestureListener>
</maps:Pushpin>
</DataTemplate>
</maps:MapItemsControl.ItemTemplate>
</maps:MapItemsControl>
</maps:Map>

Setting IsEnabled to false prevents the Map control from responding to user input, which affects the child Pushpin as you've seen. If you want the map to be read-only but the Pushpin to respond to gestures then I think you have two options:
Handle all the gesture events on the Map control and set e.Handled to true, which will prevent the Map itself from processing the event, but should leave the PushPin free to handle the tap gesture.
Create a WriteableBitmap of the Map and show that instead, and then display the Pushpin on top (NOTE: I suspect that the Pushpin control won't work outside of the Map control, so you'd need to create/re-template a control to look like a Pushpin).
UPDATE: The events that you need to handle on the Map to make it appear "read-only" but remain enabled are MapPan and MapZoom.

So here's how I solved it after a lot of testing and browsing MSDN. It turns out that things are a bit different in the Map control on Windows Phone (see MSDN). There are new behaviors and events compared to normal Silverlight.
<maps:Map Name="Map"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
CopyrightVisibility="Collapsed" LogoVisibility="Collapsed" ScaleVisibility="Collapsed" ZoomBarVisibility="Collapsed"
MapZoom="Map_MapZoom" MapPan="Map_MapPan">
<maps:MapItemsControl ItemsSource="{Binding TheCollection}">
<maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<maps:Pushpin Name="Pin" Location="{Binding Coordinate}" Content="{Binding Ix}">
<maps:Pushpin.Background>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</maps:Pushpin.Background>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="PinTap" />
</toolkit:GestureService.GestureListener>
</maps:Pushpin>
</DataTemplate>
</maps:MapItemsControl.ItemTemplate>
</maps:MapItemsControl>
</maps:Map>
...
private void Map_MapPan(object sender, MapDragEventArgs e)
{
e.Handled = true;
}
private void Map_MapZoom(object sender, MapZoomEventArgs e)
{
e.Handled = true;
}

Related

How to implement tab view in windows phone 8

In my windows application, I want to implement tab view like android tab view.
For reference please see the below image.
How should I Implement that in Windows phone 7 or 8.
I'm looking forward for your reply.
Thanks in Advance.
By default, the Windows Phone 7 SDK doesn't have a TabControl. It is a quite useful component already available in Silverlight and although it doesn't quite follow the Metro style.
Using the TabControl on Windows Phone 7 gives you better idea. Here is good example using tab control in wp7
<ListBox x:Name="lstBoxRss" SelectionChanged="lstBoxRss_SelectionChanged_1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,5">
<TextBlock x:Name="txtblkLink" Text="{Binding Title}" Foreground="Blue" TextDecorations="Underline" TextWrapping="Wrap" Tap="txtblkLink_Tap" />
<TextBlock Text="{Binding PubDate}" Foreground="Red"/>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" Foreground="Black"/>
<Button x:Name="btnOne" Content="ButtonOne" Click="btnOne_Click_1"/>
<Button x:Name="btnTwo" Content="Button Two" Click="btnTwo_Click_1"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//Code behind
private void lstBoxRss_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
//Listbox selection change
// do your work
if(lstBoxRss.SelectedIndex==-1)
return;
}
private void btnOne_Click_1(object sender, RoutedEventArgs e)
{
//First button click
//Do your work
}
private void btnTwo_Click_1(object sender, RoutedEventArgs e)
{
//button two click
//Do your work
}
There is no TabControl in the Windows Phone SDK 8. The closest equivalent is a Pivot control. You can put a row of clickable text or icons at the top of a Pivot and make it operate like a tab bar.
http://social.msdn.microsoft.com/Forums/en-US/wpdevelop/thread/1baf74fa-0ddd-4226-a02d-a7fc9f80374d
Pivot control instead of a TabControl for the WindowsPhone. the Pivot control follows the design guidelines for the phone and looks and feels much better.
For Windows phone 7 visit this Link:
http://developer.nokia.com/community/wiki/Tab_Control_in_Qt_and_Windows_Phone

WP7 discards MouseLeftButtonUp if didn't receive ButtonDown

I'm trying to get an element to fire the MouseUp event when the user clicks/taps outside of it, drags into it, then lets go. This type of functionality works in Silverlight, but not WP7. I can't figure out how to get it to work in WP7.
I created a simple app that demonstrates this. In a brand new WP7 app I added this to the content panel:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="g1" MouseLeftButtonUp="Grid_MouseLeftButtonUp" Background="Green" />
<Grid x:Name="g2" Grid.Row="1" MouseLeftButtonUp="Grid_MouseLeftButtonUp" Background="Blue" />
</Grid>
Then the Grid_MouseLeftButtonUp handler in the codebehind:
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
System.Diagnostics.Debug.WriteLine("MouseUp in " + (sender as Grid).Name);
(sender as Grid).Background = new SolidColorBrush(Colors.Red);
}
Run this app and notice the MouseUp event fires fine if you release the button in the same cell you pressed down, however it doesn't fire if you drag from one cell to the other. How can I make the MouseUp event fire?
P.S. I also posted this on the app-hub forms, but no response yet: http://forums.create.msdn.com/forums/p/98004/584400.aspx
My solution is a bit like ShawnFeatherly's, but without TouchFrame.
Basically, as he says, if you call MouseCapture from the grid where the MouseDown event occured, the MouseUp will be triggered on the same grid. So we know how to be notified when MouseUp occurs, the only problem left is how to know in which grid the MouseUp actually occured.
For this, we're going to use the VisualTreeHelper.FindElementsInHostCoordinates method, as it returns all the elements at a specified coordinate.
So, first add a MouseLeftButtonDown event handler to each of your grids:
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
((Grid)sender).CaptureMouse();
}
Now in the MouseLeftButtonUp event handler of each of your grids, first release the mouse capture, then retrieve the Grid in which the MouseUp occured:
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var grid = (Grid)sender;
grid.ReleaseMouseCapture();
var mouseUpGrid = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Grid>()
.FirstOrDefault();
if (mouseUpGrid != null)
{
Debug.WriteLine("MouseUp in " + mouseUpGrid.Name);
mouseUpGrid.Background = new SolidColorBrush(Colors.Red);
}
}
Note that a problem may occurs depending on your visual tree: if you have multiple grids and wants to detect the MouseUp only on some, you need a way to identify them. For this, I suggest to use the Tag property. Tag is an all-purpose field available on each control, that you can use however you need. It's especially useful for identification purposes.
Start by adding it to the grids that interest you:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0"
MouseLeftButtonUp="ContentPanel_MouseLeftButtonUp">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="g1"
Background="Green"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
<Grid x:Name="g2"
Grid.Row="1"
Background="Blue"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
</Grid>
Then use exactly the same logic in code-behind, but this time add a filter when browsing the visual tree:
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var grid = (Grid)sender;
grid.ReleaseMouseCapture();
var mouseUpGrid = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Grid>()
.FirstOrDefault(element => element.Tag is string && (string)element.Tag == "dragdrop");
if (mouseUpGrid != null)
{
Debug.WriteLine("MouseUp in " + mouseUpGrid.Name);
mouseUpGrid.Background = new SolidColorBrush(Colors.Red);
}
}
And you're done! This code should be able to handle complex scenarios like:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0"
MouseLeftButtonUp="ContentPanel_MouseLeftButtonUp">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="g1"
Background="Green"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
<Grid x:Name="DummyGrid" Grid.Row="1">
<Grid x:Name="g2"
Background="Blue"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
</Grid>
</Grid>
One way to work around this is listening to the TouchFrame for a TouchAction.Up. You'll have to calculate the UIElement the ButtonUp cooresponds to using the TouchPoints' Position property as described here: http://forums.create.msdn.com/forums/p/98004/584465.aspx#584465
Another way is to capture the mouse in the ButtonDown UIElement. This will cause the ButtonUp to correctly fire, however the sender will be the original UIElement that caused the ButtonDown. You can track the elements the mouse moves through using MouseEnter and MouseLeave. The necessity for mouse capture is briefly touched on here: http://forums.create.msdn.com/forums/p/70785/431882.aspx
Last time I checked, my phone didn't have a mouse attached.
Use the Tap event instead of MouseLeftButtonUp. For more complicated gestures, use the Silverlight Toolkit GestureListener class.
Use MouseLeave event
http://vantsuyoshi.wordpress.com/2012/02/01/wp7-mouseleftbuttonup-not-fired-issue/

No DataBinding when rendering a UserControl+ItemsControl in WriteableBitmap?

I want to use a WriteableBitmap to render a programmatically instantiated UserControl to a jpg/png image to use it as a live tile background image in a Windows Phone 7.1 project, but DataBinding is not working as expected when rendering the control.
In general, the UserControl is something like this:
<UserControl>
<Grid x:Name="LayoutRoot" Height="173" Width="173" >
<Grid.Background >
<SolidColorBrush Color="{StaticResource PhoneAccentColor}" />
</Grid.Background >
<Grid.RowDefinitions>
<RowDefinition Height="27"/>
<RowDefinition Height="146"/>
</Grid.RowDefinitions >
<ItemsControl Grid.Row="1" Margin="10,0,0,0" ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyBindingProperty, FallbackValue=xxx}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="Hello World" FontSize="22" Margin="5,0,0,0"/>
<TextBlock TextWrapping="Wrap" Text="{Binding Count, FallbackValue=-1}" FontSize="18.667" Margin="123,0,0,0"/>
</Grid>
</UserControl>
When I now put this control onto a PhoneApplicationPage and assign a list with items of my data structure to the DataContext property of the UserControl, everything works fine and I see one TextBlock for each list item and the Text property of that TextBlock is correctly displaying the value of the property of my data structure. Also the last TextBlock on the Grid displays correctly the current count of list items.
BUT when I'm now trying to programmatically create that UserControl, assign the same list to the DataContext and then use a WriteableBitmap to render it to an image file, it seems that all DataBindings within the DataTemplate of the ItemsControl aren't working anymore, they're displaying the FallbackValue now. Although the DataBinding of the outer TextBlock in the Grid is still working perfectly and also I got the correct number of TextBlocks in the StackPanel (= items in the bound list).
Here is my code for creating the the WriteableBitmap:
var tile = new MyTileControl { DataContext = this._myList };
tile.Arrange(new Rect(0, 0, 173, 173));
tile.Measure(new Size(173, 173));
var bmp = new WriteableBitmap(173, 173);
bmp.Render(tile, null);
bmp.Invalidate();
What's the problem with the DataBindings in the DataTemplate when rendering through a WriteableBitmap and how can I solve it?
I think, that your control not fully created yet, and you can't grab bitmap just after creation. Try to use Dispatcher.BeginInvoke or something else for delayed grabbing of image.
Also, add this control to your page and look where is a problem - in control creation or in bitmap? This give you more information about a problem.

Passing Object rather than selectedIndex from Databound listbox

I'm having an issue when I try to pass the selectedIndex of my list from my "List" screen.
On my List screen I have the following binding:
Code Behind:
lbPrograms.ItemsSource = App.ViewModel.Items;
XAML:
<ListBox x:Name="lbPrograms" ItemsSource="{Binding Items}" SelectionChanged="lbPrograms_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
<Image x:Name="ItemImage" Source="/images/ArrowImg.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
<StackPanel>
<TextBlock x:Name="ItemText" Text="{Binding programName}" Margin="-2,-13,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock x:Name="DetailsText" Text="{Binding createDate}" Margin="0,-6,0,3" Style="{StaticResource PhoneTextSubtleStyle}"/>
<TextBlock x:Name="programId" Text="{Binding programId}" Margin="0,-6,0,3" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
<!--<Image x:Name="ItemFavs" Source="/images/favs.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>
<Image x:Name="ItemDelete" Source="/images/delete.png" Height="43" Width="43" VerticalAlignment="Top" Margin="10,0,20,0"/>-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In my detail screen I look up using the selectedIndex value:
App.ViewModel.Refresh();
DataContext = App.ViewModel.Items[index].nValDictionary;
However, since I can't figure out how to just update a value in my iEnumerable collection I have been removingAt[index] and then re-adding to the collection.
So can anyone tell me, how do use update an existing element in my collection? If not, can I pass the programId (that is in my binding) instead of the selectedIndex as the indexes are getting all messed up after the Delete/Add functionality.
Please Advise.
UPDATE:
After speaking in several forums I should clear up that I am implement INotifyChanged Event on my properties in my object.
Basically the following snippet of code is my current issue:
private void FavBtn_Click(object sender, EventArgs e)
{
foreach (var item in App.ViewModel.Items)
{
if ((item.currentProgram == true) && (item.programId != index))
{
item.currentProgram = false;
}
if (item.programId == index)
{
item.currentProgram = true;
}
}
When I run this everything looks to be ok.
However, when I navigate to another page, I re-load the object and the changes are lost. It is almost like I need to save them before navigating, however, if I do a item.Save(); I get duplicates in my list.
I'm guessing you haven't implemented INotifyPropertyChanged on your Items class yet.
Implementing this will allow updates made in these objects to be updated through your data bindings.
Here's a walkthrough on how to implement INotifyPropertyChanged.
How to: Implement the INotifyPropertyChanged Interface
Is App.ViewModel.Items of type ObservableCollection<T>?
If so, when you modify a property of one of the collection items and raise a property change event (via INotifyPropertyChanged) indicating the collection property that your ListBox.ItemsSource is bound to, the DataTemplate bindings will do the rest.

Databinding with Data Template on ComboBox Select Item using LINQ

I have a little Problem.
A SP give me a several list of URLĀ“s. The Urls are binded on a Combobox.
When I Select an Item, always the Object comes to the Combobox not the Selected Value, see the code below:
<DataTemplate x:Key="Webadressen" DataType="{x:Type src2:GetWebadressenResult}" >
<StackPanel>
<Label Content="{Binding Path=Adresse}" />
</StackPanel>
</DataTemplate>
<ComboBox Width="192" IsEditable="True" Margin="2" Name="Cbox_GDWeb" ItemTemplate="{StaticResource Webadressen}" SelectionChanged="Cbox_GDWeb_SelectionChanged">
private void Cbox_GDWeb_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
GetWebadressenResult test = (GetWebadressenResult)this.Cbox_GDWeb.SelectedValue;
MessageBox.Show(test.Adresse.ToString());
this.Cbox_GDWeb.Text = test.Adresse.ToString(); /* Not Working cause the this Event calls the same Method */
}
Change your ComboBox to this
<ComboBox Width="192" IsEditable="True" Margin="2" Name="Cbox_GDWeb" DisplayMemberPath="Adresse" SelectedValuePath="Adresse" SelectedValue="{Binding Path=Adresse}">
then you wont need the Datatemplate and it will work fine
you also wont need the SelectionChange event to change your selecteditem

Resources