This project has moved. For the latest updates, please go here.

Map item implementing INotifyPropertyChanged

Apr 1, 2015 at 9:59 PM
Hello,

Any idea why a change in Latitude or Longitude of a class implementing IGeoPosition (and calling PropertyChange per property change), doesn't cause the value converter to reconvert and the map item position to be updated?
public interface IGeoPosition : INotifyPropertyChanged
{
    double Latitude { get; set; }
    double Longitude { get; set; }
    double? Altitude { get; set; }
}
public class IGeoPositionToLocationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var geoPosition = value as IGeoPosition;
        if (geoPosition != null)
            return new Location(geoPosition.Latitude, geoPosition.Longitude);
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
<map:MapItemsControl ItemsSource="{Binding Targets}"
                    ItemContainerStyle="{StaticResource TargetItemStyle}"
                    IsSynchronizedWithCurrentItem="True"/>
<Style x:Key="TargetItemStyle" TargetType="map:MapItem">
    <Setter Property="map:MapPanel.Location" Value="{Binding Converter={StaticResource IGeoPositionToLocationConverter}}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="map:MapItem">
                ...
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Coordinator
Apr 2, 2015 at 3:04 PM
Targets is a collection of objects that implement IGeoPosition? Raising a PropertyChanged event when their Latitude or Longitude values change won't trigger a binding update, because you haven't bound to these properties.
Apr 2, 2015 at 5:39 PM
Thank you for replying.

Yes, Targets is a BindingList<IGeoPosition> which afaik has ListChanged (being called, I've verified), so I thought this should work "out of the box".

How is it possible to trigger a binding update for the map item when I change Latitude or Longitude?
For some reason I'm struggling this since CodePlex latest discussions outage :)

Thanks!
Coordinator
Apr 2, 2015 at 6:56 PM
Edited Apr 2, 2015 at 6:58 PM
In this case, where you bind directly to the objects in the collection, you need to replace objects in order to update the UI, because the binding will only update when there is a new value of the bound property, i.e. a new instance of the collection item.

An alternative would be a collection of objects that have a property of type IGeoPosition, like
public class DataItem : INotifyPropertyChanged
{
    IGeoPosition Position { get; set; } // raise PropertyChanged here
}
Then write the binding like this:
<Setter Property="map:MapPanel.Location"
    Value="{Binding Position, Converter={StaticResource IGeoPositionToLocationConverter}}"/>
Apr 2, 2015 at 8:28 PM
Well, both solutions are quite similar, if I understand you correctly.

Wouldn't this be MUCH nicer :-)
<Setter Property="map:MapPanel.Latitude" Value="{Binding Latitude}"/>
<Setter Property="map:MapPanel.Longitude" Value="{Binding Longitude}"/>
Binding updateable, no converter, cleaner. What do you think?

Thanks!
Coordinator
Apr 2, 2015 at 8:32 PM
Edited Apr 2, 2015 at 8:33 PM
I don't think so. You would always have two attached properties for one "logical" location property.
Apr 3, 2015 at 7:18 AM
But what if that one "logical" location property changes internally? It seems that currently there's no way to propagate this.
Think of a DataGrid also binding to that Targets collection, with editable Latitude and Longitude columns. Or a live feed updating those targets, etc..

How about XamlMapControl binding programmatically to Latitude and Longitude? Is this feasible? Or maybe there's a way to tell WPF to trigger an update on property changes?

Thanks.
Apr 10, 2015 at 8:01 PM
Clemens, you were right.
public class DataItem : INotifyPropertyChanged
{
    IGeoPosition Position { get; set; } // raise PropertyChanged here
}
Worked, but ONLY AFTER I defined Mode as OneWay:
<Setter Property="map:MapPanel.Location" Value="{Binding Position, Converter={StaticResource GeoPositionToLocationConverter}, Mode=OneWay}"/>
Any idea why?