Select to view content in your preferred language

Changing Layers DefaultVisibility with PRISM causing an error

1004
4
Jump to solution
06-12-2012 12:48 PM
DaviKucharski
Deactivated User
I previously had a thread (http://forums.arcgis.com/threads/59678-Binding-Layers-of-Map-within-Prism-(MVVM)) about getting my layers to show. Joe and Jennifer solved the issue different ways. Now with the same code base I am getting an error trying to update the DefaultVisibility on the Layers.

Here is my code behind in my ViewModel. You will see I now subscribe to an event called MapLayersUpdated. This calls a function called updateLayerList that takes an ObservableCollection<LayerModel> parameter. The LayerModel is just a class that has 3 properties (ID, Name, DefaultVisibility). In the updateLayerList function I create a new LayerCollection and get the ArcGISDynamicMapServiceLayer from my map object.

I then set up a List of integers to keep the Visible layers that came in from the LayerList parameter. I set the VisibleLayers to this array, add the layer to my LayersCollection and then call my BaseMapLayerService property that I use to Bind to the Layers element of my map in the XAML. The property calls a OnPropertyChanged("BaseMapLayerService"). When that is called I get an error "". This does not happen if I use the same logic but use a Textbox and string for element and data respectively. I don't know if it is an ESRI issue or something else.

XAML:
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"                x:Class="Geomentum.MediaReach.Modules.Map.View.MapView"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d"      xmlns:esri="http://schemas.esri.com/arcgis/client/2009"     xmlns:local="clr-namespace:Geomentum.MediaReach.Modules.Map.View"     xmlns:ViewModel="clr-namespace:Geomentum.MediaReach.Modules.Map.ViewModel">         <esri:Map x:Name="MyMap" WrapAround="True" IsLogoVisible="False" Layers="{Binding ViewModel.BaseMapLayerService}" /> </UserControl>


ViewModel:
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Geomentum.MediaReach.Modules.Map.View; using Microsoft.Practices.Prism.Events; using System.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; using Geomentum.MediaReach.Infrastructure.Models; using Geomentum.MediaReach.Infrastructure.Events; using ESRI.ArcGIS.Client;   namespace Geomentum.MediaReach.Modules.Map.ViewModel {     public class MapViewModel : IMapViewModel, INotifyPropertyChanged      {         private readonly IEventAggregator eventAggregator;         private ESRI.ArcGIS.Client.LayerCollection _baseMapLayerService;         private MediaReachMap _map;         public IMapView View { get; set; }          public MapViewModel(IMapView view, IEventAggregator eventAggregator, MediaReachMap map)         {             View = view;             View.Model = this;             _map = map;              BaseMapLayerService = CreateMapLayers(map);             this.eventAggregator = eventAggregator;              this.eventAggregator.GetEvent<MapLayersUpdated>().Subscribe(this.updateLayerList);         }          public ESRI.ArcGIS.Client.LayerCollection BaseMapLayerService         {             get { return this._baseMapLayerService; }             set             {                 this._baseMapLayerService = value;                 OnPropertyChanged("BaseMapLayerService");             }         }          public void updateLayerList(ObservableCollection<LayerModel> LayerList)         {              ESRI.ArcGIS.Client.LayerCollection layers = new ESRI.ArcGIS.Client.LayerCollection();             ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer baseLayer = _map.MapLayerService;               List<int> visibleLayerIDList = new List<int>();             ESRI.ArcGIS.Client.LayerInfo[] layerInfoArray = baseLayer.Layers;              for (int index = 0; index < layerInfoArray.Length; index++)             {                 if (LayerList[index].DefaultVisibility)                     visibleLayerIDList.Add(index);             }              baseLayer.VisibleLayers = visibleLayerIDList.ToArray();              layers.Add(baseLayer);              BaseMapLayerService = layers;         }          private ESRI.ArcGIS.Client.LayerCollection CreateMapLayers(MediaReachMap map)         {             ESRI.ArcGIS.Client.LayerCollection layers = new ESRI.ArcGIS.Client.LayerCollection();              //create the base map layer             ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer baseLayer = new ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer()             {                 ID = "BaseLayer",                 Url = map.BaseMapURL             };             layers.Add(baseLayer);              return layers;         }          #region INotifyPropertyChanged Members         public event PropertyChangedEventHandler PropertyChanged;         private void OnPropertyChanged(string propertyName)         {             PropertyChangedEventHandler handler = this.PropertyChanged;             if (handler != null)             {                 handler(this, new PropertyChangedEventArgs(propertyName));             }         }         #endregion     } }


[ATTACH=CONFIG]15154[/ATTACH]
0 Kudos
1 Solution

Accepted Solutions
JoeHershman
MVP Alum
I believe there is some oddity with when you can set the VisibleLayers array and have it work like you expect, like only during initialization.  Other times you want to use the SetVisibility method.  I think this will accomplish what you are trying to do

        public void updateLayerList(ObservableCollection<LayerModel> LayerList)         {              ESRI.ArcGIS.Client.LayerCollection layers = new ESRI.ArcGIS.Client.LayerCollection();             ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer baseLayer = (ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer)this._baseMapLayerService[0];              List<int> visibleLayerIDList = new List<int>();              ESRI.ArcGIS.Client.LayerInfo[] layerInfoArray = baseLayer.Layers;              for ( int index = 0; index < layerInfoArray.Length; index++ )             {                 baseLayer.SetLayerVisibility(index, LayerList[index].DefaultVisibility);             }              //You should not not need these lines - I think :)             this._baseMapLayerService[0] = baseLayer;             OnPropertyChanged("BaseMapLayerService");         }


Also, I think those last to lines are not really needed.  the baseLayer variable is a reference to _baseMapLayerService[0] so by changing it you are effectively changing _baseMapLayerService[0].  ESRI takes care of firing off the necessary events on the Layer object so no need to fire your own.  Also because the Map::LayerCollection itself is an ObservableCollection anytime you add or remove layers from your BaseMapLayerService those changes will be reflected in the map, no need to fire off an OnPropertyChanged.

Hope that helps
-Joe
Thanks,
-Joe

View solution in original post

0 Kudos
4 Replies
JoeHershman
MVP Alum
What is _map.MapLayerService and where does this enter into things?  Seems you could just change the VisibleLayers array on that and it would achieve you goal.

Hard to say without knowing more.  Are there more details about the error being received?

-Joe

btw:  PRISM has a Microsoft.Practices.Prism.ViewModel.NotificationObject which implements INotifyPropertyChanged and exposes a RaisePropertyChanged so you can inherit from that object instead of having to implement INotifyPropertyChanged in every ViewModel
Thanks,
-Joe
0 Kudos
DaviKucharski
Deactivated User
Joe,

I changed the updateLayerList function to the following:
I retrieve my BaseLayer from my local _baseMapLayerService (LayerCollection) that I used to bind the Layers to using the BaseMapLayerService property. I then loop through the sub-layers and set the DefaultVisibility. I then set the baseLayer object back into my local LayerCollection this._baseMapLayerService[0]. Then call the PropertyChange method. I do not get an error anymore, but my map disappears after I set the DefaultVisibility. I have about 30 layers under my base layer with about 20 of them visible. I am turning 1 off so I should still have a map. Any thoughts? Do I need some type of Initialized function again?


        public void updateLayerList(ObservableCollection<LayerModel> LayerList)
        {

            ESRI.ArcGIS.Client.LayerCollection layers = new ESRI.ArcGIS.Client.LayerCollection();
            ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer baseLayer = (ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer)this._baseMapLayerService[0];

            List<int> visibleLayerIDList = new List<int>();
            ESRI.ArcGIS.Client.LayerInfo[] layerInfoArray = baseLayer.Layers;

            for (int index = 0; index < layerInfoArray.Length; index++)
            {
                if (LayerList[index].DefaultVisibility)
                    visibleLayerIDList.Add(index);
            }

            baseLayer.VisibleLayers = visibleLayerIDList.ToArray();
            this._baseMapLayerService[0] = baseLayer;
            OnPropertyChanged("BaseMapLayerService");
        }
0 Kudos
JoeHershman
MVP Alum
I believe there is some oddity with when you can set the VisibleLayers array and have it work like you expect, like only during initialization.  Other times you want to use the SetVisibility method.  I think this will accomplish what you are trying to do

        public void updateLayerList(ObservableCollection<LayerModel> LayerList)         {              ESRI.ArcGIS.Client.LayerCollection layers = new ESRI.ArcGIS.Client.LayerCollection();             ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer baseLayer = (ESRI.ArcGIS.Client.ArcGISDynamicMapServiceLayer)this._baseMapLayerService[0];              List<int> visibleLayerIDList = new List<int>();              ESRI.ArcGIS.Client.LayerInfo[] layerInfoArray = baseLayer.Layers;              for ( int index = 0; index < layerInfoArray.Length; index++ )             {                 baseLayer.SetLayerVisibility(index, LayerList[index].DefaultVisibility);             }              //You should not not need these lines - I think :)             this._baseMapLayerService[0] = baseLayer;             OnPropertyChanged("BaseMapLayerService");         }


Also, I think those last to lines are not really needed.  the baseLayer variable is a reference to _baseMapLayerService[0] so by changing it you are effectively changing _baseMapLayerService[0].  ESRI takes care of firing off the necessary events on the Layer object so no need to fire your own.  Also because the Map::LayerCollection itself is an ObservableCollection anytime you add or remove layers from your BaseMapLayerService those changes will be reflected in the map, no need to fire off an OnPropertyChanged.

Hope that helps
-Joe
Thanks,
-Joe
0 Kudos
DaviKucharski
Deactivated User
Joe,

Once again you are correct. I found the SetLayerVisibility function about 2 minutes before your post. I also noticed it changed without the PropertyNotify.

Probably have more questions for you soon.

Thanks again.
0 Kudos