0
votes

I am working on a location aware app, where I want to have custom pushpins that have an image, and when you tap the image, a label is added. I have tried a couple of solutions...

I started with this code, from this article: http://igrali.wordpress.com/2011/12/06/making-a-custom-windows-phone-bing-pushpin-from-an-image/

<ControlTemplate
        x:Key="PushpinMe"
        TargetType="maps:Pushpin">
        <Grid
            Name="PushpinMeGrid"
            Height="50"
            Width="50"
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Image
                    x:Name="PushpinMeImage"
                    Height="50"
                    Width="50"
                    Source="Pushpins/pushpinSeaplane.png" />
            <TextBlock Text="{Binding Source=}"
        </Grid>
    </ControlTemplate>

Then I tried wrapping the image in a button, but that just made the pushpin essentially invisible. Then I tried using a control template from one of my prior apps, and modified it, and came up with this:

        <Button
            Name="PushpinButton"
            Click="Button_Click">
            <Button.Style>
                <Style
                    TargetType="Button">
                    <Setter
                        Property="Template">
                        <Setter.Value>
                            <ControlTemplate
                                TargetType="Button">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition
                                            Width="*" />
                                        <ColumnDefinition
                                            Width="*" />
                                    </Grid.ColumnDefinitions>
                                    <Image
                                        Grid.Column="0"
                                        Grid.Row="0"
                                        Grid.RowSpan="2"
                                        Height="50"
                                        Width="50"
                                        Source="Pushpins/pushpinSeaplane.png" />

                                    <Grid
                                        Grid.Column="1">

                                        <Grid.RowDefinitions>
                                            <RowDefinition
                                                Height="39" />
                                            <RowDefinition
                                                Height="*" />
                                        </Grid.RowDefinitions>

                                        <Grid
                                            Grid.Row="0"
                                            Background="Black">
                                            <TextBlock
                                                Grid.Row="0"
                                                Foreground="White"
                                                Text="{Binding ElementName=me,
                                                  Path=Content}"
                                                TextWrapping="Wrap"
                                                Margin="5" />
                                        </Grid>
                                    </Grid>
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Button.Style>
        </Button>

    </ControlTemplate>

Still not a winner - I can't bind the content of the button, and therefore the textblock.

There will be a series of pushpins, with different images, and different labels, so ideally, I would like to come up with a template that I can use, and bind the image and the label from code. The code for the button's click event would be as simple as making the textblock visible or collapsed.

I know my second example is pretty ugly, but I was trying to make the visual look right - I'll modify it as needed for the visuals, but for the moment, I need to figure out how I can bind the image and the text from code. The button click event works with just a messagebox for now (to show that it registered the click event).

Thanks for your assistance.

1

1 Answers

0
votes

Sounds like a fun project! I've implemented databinding on nested content controls within a button before using declarations similar to the following. So in your case the push pin collection would be bound to the items control with each push pin object providing the data for its corresponding button (including the button's nested image and textblock).

Let's take a look at a simple example that I hope will guide you in the right direction.

To start here's an example of a button template that you could define in the resource dictionary of your choosing. Note the visibility binding on the image and the text binding on the textblock, these properties will be located on a Pushpin_ViewModel we'll define later:

    <Style x:Name="PushpinButtonStyle" TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused"/>
                                <VisualState x:Name="Unfocused"/>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver" />
                                <VisualState x:Name="Pressed"/>
                                <VisualState x:Name="Disabled"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Image Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Height="50" Width="50" Source="Pushpins/pushpinSeaplane.png" Visibility="{Binding PushpinImageVisibility}" />
                        <Grid Grid.Column="1">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="39" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <Grid Grid.Row="0" Background="Black">
                                <TextBlock Grid.Row="0" Foreground="White"  Text="{Binding PushpinLabelText}" TextWrapping="Wrap" Margin="5" />
                            </Grid>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

In your primary view where your pushpins are displayed you may have some sort of items control responsible for displaying your pushpins. Here is an example of such an items control where the data template is a button with two important features 1) the button style we defined above and 2) a click event that will call a toggle method on the corresponding pushpin view model:

<ItemsControl ItemsSource="{Binding Pushpins}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Name="PushpinButton" Click="pushpinButton_Click" DataContext="{Binding}" Style="{StaticResource PushpinButtonStyle}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

private void pushpinButton_Click(object sender, RoutedEventArgs e)
{
    Pushpin_ViewModel pushpin_ViewModel = ((Button)sender).DataContext as Pushpin_ViewModel;
    pushpin_ViewModel.TogglePushpinVisibility();
}

The following view model class would represent the data context of your primary view (the one that contains the items control we defined above). Here we have the collection of pushpins that populate the items control:

public class PrimaryPushpinView_ViewModel : INotifyPropertyChanged
{
    public PushpinView_ViewModel()
    {
        this.Pushpins.Add(new Pushpin_ViewModel() { PushpinLabelText="First Pushpin" });
    }

    public List<Pushpin_ViewModel> Pushpins
    {
        get { return pushpins; }
        set
        {
            if (value != pushpins)
            {
                pushpins = value;
                OnPropertyChanged("Pushpins");
            }
        }
    }
    private List<Pushpin_ViewModel> pushpins = new List<Pushpin_ViewModel>();
}

And finally here is a representation of the pushpin view model. There would be one instance of this class per pushpin in your pushpin collection:

public class Pushpin_ViewModel : INotifyPropertyChanged
{
    public Visibility PushpinVisibility
    {
        get { return pushpinVisibility; }
        set
        {
            if (value != pushpinVisibility)
            {
                pushpinVisibility= value;
                OnPropertyChanged("PushpinVisibility");
            }
        }
    }
    private Visibility pushpinVisibility;

    public String PushpinLabelText
    {
        get { return pushpinLabelText; }
        set
        {
            if (value != pushpinLabelText)
            {
                pushpinLabelText= value;
                OnPropertyChanged("PushpinLabelText");
            }
        }
    }
    private String pushpinLabelText;

    public void TogglePushpinVisibility()
    {
        this.PushpinVisibility = this.PushpinVisibility.Equals(Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible;
    }
}

Sorry it took a while to get back to you, crazy day today, hope this helps out.