MSDN Magazine - December 2007 - (Page 49) Figure 4 MapPolygon.vb Public Class MapPolygon Inherits DependencyObject Private Shared ReadOnly RegionPropertyKey As DependencyPropertyKey _ = DependencyProperty.RegisterReadOnly(“Region”, _ GetType(MapRegion), GetType(MapPolygon), New PropertyMetadata()) Public Shared ReadOnly RegionProperty As DependencyProperty Private m_Points As PointCollection Shared Sub New() RegionProperty = RegionPropertyKey.DependencyProperty End Sub Sub New() SetRegion(Nothing) m_Points = New PointCollection End Sub Friend Sub SetRegion(ByVal r As MapRegion) SetValue(RegionPropertyKey, r) End Sub Public ReadOnly Property Region() As MapRegion Get Return CType(GetValue(RegionProperty), MapRegion) End Get End Property Public ReadOnly Property Points() As PointCollection Get Return m_Points End Get End Property End Class dler is shown in Figure 5. It works by calling the SetRegion extension method on the NewItems and OldItems collections stored in the handler’s NotifyCollectionChangedEventArgs parameter. The extension method then calls the MapPolygon class’s SetRegion method on each item in the target collection. The instance method is marked as friend to discourage it from being called. The extension method implementation looks like this: _ Sub SetRegion(ByVal x As IEnumerable(Of MapPolygon), _ ByVal r As MapRegion) For Each item In x item.SetRegion(r) Next End Sub Unlike the collection properties on the Map and MapRegion classes, the Points collection on the MapPolygon class is not an ObservableCollection(of T). Instead it uses the built-in WPF PointsCollection class. This is the same type that the WPF Polygon control uses to store the set of points it contains. By using this class in the data model, it is then possible to data bind a Polygon control directly to a MapPolygon instance. Importing Map Data The application loads its map data from XML files stored on disk. I created these files by downloading raw ASCII cartographic boundary files from the U.S. Census Bureau, which describe the boundaries of every state and county (and equivalent areas) within the United States. The state boundary data is used to draw a map of the United States and the county boundary data is used to visualize population data on the map. I then took the downloaded data and converted it into XML files for easier processing. The code for converting the files into XML is available in this article’s download. The raw data files can be downloaded at census.gov/geo/ The Region property is exposed as a read-only dependency property. This allows the WPF property system to detect changes to the property value but does not allow it to be modified by WPF. A read-only dependency property is declared by calling the RegisterReadOnly method of the DependencyProperty www/cob/bdy_files.html. class. Unlike the Register method, RegisterReadOnly returns Using the Visual Studio Create Schema feature, I then automata DependencyPropertyKey instance instead of returning a DependencyProperty. Figure 5 MapRegion.PolygonCollectionChanged Method A dependency property key is an object that allows read-only Private Sub PolygonCollectionChanged(ByVal sender As Object, ByVal e As _ dependency properties to be modified. They are useful for impleSystem.Collections.Specialized.NotifyCollectionChangedEventArgs) _ menting classes that need to update property values internally and Handles m_polygons.CollectionChanged Select Case e.Action have those changes detected by other types but do not allow external Case Specialized.NotifyCollectionChangedAction.Add modification of the value. As a result, DependencyPropertyKeys e.NewItems.Cast(Of MapPolygon).SetRegion(Me) Case Specialized.NotifyCollectionChangedAction.Remove are generally not exposed from the class that defines them. That e.OldItems.Cast(Of MapPolygon).SetRegion(Nothing) is why the RegionPropertyKey field is marked as private. A secCase Specialized.NotifyCollectionChangedAction.Replace e.NewItems.Cast(Of MapPolygon).SetRegion(Me) ond shared field, RegionProperty, is then used to publicly expose e.OldItems.Cast(Of MapPolygon).SetRegion(Nothing) End Select a read-only alias of it. End Sub The Region property is read-only because it was designed to not be externally editable. Instead, the MapRegion class will automatically set and clear the value as a polygon is added or removed from its region collection. It does this by handling the CollectionChangedEvent for the polygon collection and propagating the appropriate Region instance through to the affected polygons. The implementation of the event han- Figure 6 Visual Basic XML IntelliSense Map LINQ december2007 49 http://www.census.gov/geo/www/cob/bdy_files.html http://www.census.gov/geo/www/cob/bdy_files.html
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.