WPF Markers binding

Topics: WPF
Jul 15, 2010 at 4:24 PM
Hi, Just try to use this grate library but all time catch my self on idea about not "right" Markers work :( Present such grate thing like Filter for ICollectionView to use as DataContext. Using it no need make data dublications (one collection for program and onother in Markers), easy work with filtering, etc. P.S. Maybe I lost somthing and it's all already work but over Demo project I can't see this :(
Coordinator
Jul 16, 2010 at 4:03 AM

// set filter
ListCollectionView View = CollectionViewSource.GetDefaultView(MainMap.Markers) as ListCollectionView;
View.Filter = FilterOutMarkers;

bool FilterOutMarkers(object item)
{
         var vl = item as GMapMarker;

         if(vl == null)
            return false;

         return true;
}

..you can use your own collection instead of MainMap.Markers too

 

Jul 16, 2010 at 9:08 AM

Thank you,

But it's left us with GMapMarker. And keep require dublication of data.

In real projects goelocation data it's only small part of data related to object / overlay.

Even in your demo you made saparate lists for data and markers : trolleybus, trolleybusMarkers.

More "right" will be use interfase and require list of interfaces. So no need dublicate data and handle 2 separate lists.

Coordinator
Jul 16, 2010 at 11:04 AM

be welcome to provide me nice fork with 'right' interfaces ;}

Jul 16, 2010 at 11:15 AM

Sorry if you feal I try teach you :(

In current implementation you can't move out from GMapMarker :(

As I can see you use it not only to hold data but also to make some internal calculations.

I find older discussion about markers bindning, maybe in current state it's really more simple to extending GMapMarker.

Coordinator
Jul 16, 2010 at 2:35 PM

well if you have better idea, please share ;}

Jul 17, 2010 at 5:09 PM

Change GMapMarker to somthing like:

   public interface IGMapMarker : INotifyPropertyChanged
   {
      public UIElement Shape {get; set;}
      public PointLatLng Position {get; set;}
      public System.Windows.Point Offset {get; set;}
      public int ZIndex {get; set;}
      public List<PointLatLng> Route = {get;}
      public List<PointLatLng> Polygon = {get;}
   }

Move UpdateLocalPosition and other "calculation" methods from it to GMapControl or another internal marker handler.

Coordinator
Jul 17, 2010 at 6:07 PM

and what exactly of improvement is it?

Jul 18, 2010 at 2:31 PM

As you know in C# you can extend only 1 parent class but implement many interfaces.

In my project goe data transfer over WCF , json, http. PC program is small part of it so I try unificate classes as more as possible. Extend your class make some limitations and additional code for now.

Coordinator
Jul 18, 2010 at 2:47 PM

but isn't it simpler to keep markers in different list?

Jul 18, 2010 at 3:36 PM

Sorry but not, in and of all one of team member forgot about separate list and problems comes up.

Coordinator
Jul 18, 2010 at 4:40 PM

..so how do you suppose it can work only with interfaces? How to update local position when geo position changes?

Jul 18, 2010 at 4:52 PM

One of next:

1. Add more fields in interface.

2. Create internal list of positions.

Sorry but as usual all "content" related to control must be inside control. It will be strange if in datagrid information about column width save in data field.

Ofcourse it's only my dreams of better world and you can stay with your vision :) it already work :)

Coordinator
Jul 18, 2010 at 5:13 PM

it has nothing to do with visions ;] can you make working fork using interfaces?

Jul 19, 2010 at 10:06 AM

Somthing like that (it's just simple class for just replace current GMapMarker for use interface):

    public interface IGMapMarker : INotifyPropertyChanged
    {
        UIElement Shape { get; set; }
        PointLatLng Position { get; set; }
        System.Windows.Point Offset { get; set; }
        int ZIndex { get; set; }
        List<PointLatLng> Route { get; }
        List<PointLatLng> Polygon { get; }
    }

    public class NewGMapMarker : IGMapMarker
    {
        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }


        UIElement shape;
        public UIElement Shape
        {
            get { return shape; }
            set
            {
                if (shape != value)
                {
                    shape = value;
                    OnPropertyChanged("Shape");
                }
            }
        }

        PointLatLng position;
        public PointLatLng Position
        {
            get { return position; }
            set
            {
                if (position != value)
                {
                    position = value;
                    OnPropertyChanged("Position");
                }
            }
        }

        System.Windows.Point offset;
        public System.Windows.Point Offset
        {
            get { return offset; }
            set
            {
                if (offset != value)
                {
                    offset = value;
                    OnPropertyChanged("Offset");
                }
            }
        }

        int zIndex;
        public int ZIndex
        {
            get { return zIndex; }
            set
            {
                if (zIndex != value)
                {
                    zIndex = value;
                    OnPropertyChanged("ZIndex");
                }
            }
        }

        public List<PointLatLng> Route { get { return null; } }
        public List<PointLatLng> Polygon { get { return null; } }
    }

Ofcourse it will not work in current state. It will require to change controll, add internal Marker manager to calculate position, etc. Sorry monday havy day here :(
Coordinator
Jul 19, 2010 at 11:00 AM

how to update local position?

Jul 19, 2010 at 11:21 AM

Update can be done on property change event by internal control code that handle this event.

To save position you can add 2 fields into interface and save position here. Or you can create internal list fo save positions here.

Coordinator
Jul 19, 2010 at 11:27 AM

how to handle position changed event?

Jul 19, 2010 at 12:45 PM
Work well with previouse code.
And YES, need extend standard ObservableCollection
    class Class1
    {
        myObservableCollection<NewGMapMarker> tt = new myObservableCollection<NewGMapMarker>();
        public Class1()
        {
            tt.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(tt_CollectionChanged);
            tt.ItemPropertyChanged += new PropertyChangedEventHandler(tt_ItemPropertyChanged);
            tt.Add(new NewGMapMarker());
            tt[0].ZIndex = 100;
            tt[0].ZIndex = 200;
            NewGMapMarker tr = tt[0];
            tt.RemoveAt(0);
            tr.ZIndex = 300;
            tt.Clear();
        }

        void tt_ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
        }

        void tt_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

        }
    }

    public class myObservableCollection<T> : ObservableCollection<T>
    {
		public myObservableCollection() : base() { }

		public myObservableCollection(IEnumerable<T> data) : base(data) { }

        public event PropertyChangedEventHandler ItemPropertyChanged;

        protected override void InsertItem(int index, T item)
        {
            base.InsertItem(index, item);

            (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(myObservableCollection_PropertyChanged);
        }

        protected override void RemoveItem(int index)
        {
            (this[index] as INotifyPropertyChanged).PropertyChanged -= myObservableCollection_PropertyChanged;
            base.RemoveItem(index);
        }

        void myObservableCollection_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (ItemPropertyChanged != null)
            {
                ItemPropertyChanged(sender, e);
            }
        }
    }
Coordinator
Jul 19, 2010 at 6:22 PM

but users can set heir own collections, map.ItemSource = theirCoolCollection

so how do we handle that? ;}

Jul 19, 2010 at 6:43 PM
Inicialize any collection with
 
            if (tt is INotifyCollectionChanged)
            {
                tt.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(tt_CollectionChanged);
            }

        void tt_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (INotifyPropertyChanged item in e.NewItems)
                {
                    item.PropertyChanged += new PropertyChangedEventHandler(tt_ItemPropertyChanged);
                }
            }
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            {
                foreach (INotifyPropertyChanged item in e.OldItems)
                {
                    item.PropertyChanged -= tt_ItemPropertyChanged;
                }
            }
        }

Not require custom collection class. And if user try use not ObservableCollection - control will not work in new way or in old way.
Coordinator
Jul 20, 2010 at 7:16 AM

hm.. ok, now wondering how to update LocalPosition{XY} ?

Jul 20, 2010 at 8:36 AM
dmytyar wrote:

One of next:

1. Add more fields in interface.

2. Create internal list of positions.

I was already write this.
Coordinator
Jul 20, 2010 at 8:56 AM

just localposition should be internal...

Jul 20, 2010 at 9:22 AM

Under internal I mean in your control not in client data.

Jul 14, 2013 at 9:00 PM
Hi radioman,

Any progress regarding dmytyar's great advice on interfacing markers?

For the past few weeks I've been implementing "custom" markers which aren't a "Route" nor "Polygon".
Overriding RegeneratePolygonShape/RegenerateRouteShape is a nasty hack :) Also found myself separating data and markers (e.g. trolleybus, trolleybusMarkers).

I think we/you must do this right, meaning IGMapMarker which the map will know and use, plus GMapMarkerRoute and GMapMarkerPolygon implementing IGMapMarker for "backward" compatibility and/or basic usage.

I'll try catching you via IRC tomorrow, thanks.

Superware
Coordinator
Jul 15, 2013 at 8:22 AM
nop ;/
Jul 15, 2013 at 12:53 PM
dymtyar, how did you solve this?
Jul 22, 2013 at 12:16 PM
radioman, I'm looking for you in #gmap.net for days :)
Coordinator
Jul 22, 2013 at 12:25 PM
i'm there ;}
Aug 23, 2013 at 12:09 PM
I also think it's a real pain to create your own custom markers. Maybe the IGMapMarker-way is a good idea!
Is there already any progression on this?
Coordinator
Aug 23, 2013 at 1:30 PM
unimplemented ideas doesn't work ;}
Aug 23, 2013 at 1:37 PM
Radioman, hi, can you please join #gmap.net on IRC? angelag1, you too :)
I have a constructive suggestion.
Aug 27, 2013 at 2:03 PM
Hi radioman, angelag1 and myself are there waiting for you, it would be great if you join #gmap.net :)