// (c) Copyright ESRI.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
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 System.Collections.Generic;
using System.ComponentModel;
#if NET35
using Microsoft.Windows.Controls;
#endif
namespace ESRI.ArcGIS.Client.Toolkit
{
///
/// The Bookmark Control allows for setting pre-defined Map.Extent values using a name for speedy navigation
/// of the Map.
///
///
///
/// The Bookmark is a User Interface (UI) control that allows clients to define preset
/// Map.Extent values using a name for quick navigation in the
/// Map Control. The Bookmark Control can be created in at design time in XAML or dynamically at runtime in the
/// code-behind. The Bookmark Control is one of several controls available in the Toolbox in Visual Studio when
/// the ESRI ArcGIS API for Silverlight/WPF is installed, see the following screen shot:
///
///
///
///
///
/// The default appearance of the Bookmark Control can be modified using numerous inherited Properties from
/// System.Windows.FrameworkElement, System.Windows.UIElement, and System.Windows.Controls. An example of some
/// of these Properties include: .Height, .Width, .BackGround, .BorderBrush, .BorderThickness, .FontFamily,
/// .FontSize, .FontStretch, .FontStyle, .Foreground, .HorizontalAlignment, .VerticalAlignment, .Margin,
/// .Opacity, .Visibility, etc.
///
///
/// Note: you cannot change the core behavior of the sub-components (i.e. Button, DataGrid, etc.) of the
/// Bookmark Control using standard Properties or Methods alone. To change the core behavior of the
/// sub-components and their appearance of the Control, developers can modify the Control Template in XAML
/// and the associated code-behind file. The easiest way to modify the UI sub-components is using Microsoft
/// Expression Blend. Then developers can delete/modify existing or add new sub-components in Visual Studio
/// to create a truly customized experience. A general approach to customizing a Control Template is discussed
/// in the ESRI blog entitled:
/// Use control templates to customize the look and feel of ArcGIS controls.
/// Specific code examples of modifying the Control Template of the Bookmark control to can be found in the
/// Bookmark.DeleteBookmarkAt Method
/// and Bookmark.AddBookmark Method
/// documents.
///
///
/// In order to use the Bookmark Control it is mandatory that the
/// Bookmark.Map Property be set to a Map Control.
/// This can be done via Binding in the XAML or by setting the Map Property in the code-behind file.
///
///
/// The Bookmark Control is comprised of mainly five sub-components:
///
/// -
/// A TextBlock for displaying the Bookmark.Title
///
/// -
/// A TextBox to provide a Name for the Map.Extent of the
/// MapBookmark item
///
/// -
/// A Button to add the named Map.Extent
/// (aka. a bookmark) to the DataGrid
///
/// -
/// A DataGrid to display the ObservableCollection(Of Bookmark.MapBookmark)
/// that have been added by the user
///
/// -
/// A Button to clear out (or remove)
/// all of the MapBookmark items from the DataGrid
///
///
///
///
/// The following image shows a typical Bookmark Control and its various sub-component parts:
///
///
///
///
///
/// To use the Bookmark Control, clients use the various pan/zoom functions on the Map Control to select a
/// visual Map.Extent and then type in a name for in the TextBox. Then they click the + button to add
/// that named Map.Extent (aka. a bookmark) into the DataGrid. Later when the user decides to go back to a
/// previous Map.Extent, they click on the name in the DataGrid and the Map will automatically pan/zoom to
/// that named Map.Extent (aka. a bookmark). Users click the Clear button to remove all of the named Map.Extent
/// (aka. a bookmark) values from the DataGrid.
///
///
/// If a portion of the current Map.Extent is in the named Map.Extent (aka. a bookmark) when the user clicks on
/// a bookmark item in the DatGrid, the map will pan/zoom using an animation to the clicked bookmark. If the
/// current Map.Extent does not contain any spatial overlap with the named Map.Extent (aka. a bookmark) that
/// the user clicks on in the DataGrid, there will be not be any animation and the Map will immediately go to
/// the new Bookmark location.
///
///
/// By default the ESRI.ArcGIS.Client.Toolkit.Bookmark.UseIsolatedStorage
/// value equals True. This means that the application will remember from one session to another the named
/// Map.Extent (aka. a bookmark) values previously entered. If the Bookmark.UseIsolatedStorage is set to False,
/// the next time a user begins another client session of the application the named Map.Extent (aka. a bookmark)
/// settings will be lost. Note: There is only one IsolatedStorage container per application.
/// This may have implications if you have multiple Maps, each with their own set of Bookmarks. This means you
/// may need to make use of the Bookmark.Bookmarks
/// Property which returns an ObservableCollection(Of Bookmark.MapBookmark) object to persist across the various
/// Maps.
///
///
/// When a Bookmark Control is created the ObservableCollection (Of MapBookmark) object is also created that is
/// accessible from the Bookmark.Bookmarks Property. Although the Bookmark.Bookmarks Property is ReadOnly,
/// meaning you can only get the ObservableCollection (Of MapBookmark) object, you can use its Members to like:
/// Add, Clear, Remove, etc. to define how the Bookmark Control behaves.
///
///
/// To change the text of a previously entered named Map.Extent (aka. a bookmark) in the DataGrid, click on the
/// text portion inside of the selected DataGrid item and the bounding box around the text will turn Black
/// (meaning it is ready to accept the cursor for text changes). Then type the desired edits and when done making
/// text changes for the named Map.Extent (aka. a bookmark) click with the mouse cursor somewhere outside of the
/// editiable portion of the DataGrid. It may take some practice of first selecting a DataGrid item and then
/// clicking on the text inside of the DataGrid to get the Black editable background (two clicks in the same spot
/// but not a double-click).
///
///
/// When the user types in a name for the current Map.Extent to add to the DataGrid by clicking the +
/// button, the text value that is typed will remain after the user clicks the + button. The text value
/// does not automatically clear when the + button is clicked.
///
///
/// It is possible to programmatically control the removal of one named Map.Extent (aka. a bookmark) from the
/// DataGrid in the Bookmark Control rather than removing all of them via the Clear button. Use the
/// Bookmark.DeleteBookmarkAt Method to
/// supply an index number for the correct named Map.Extent (aka. a bookmark) in the DatGrid to be removed. The
/// visually top most named Map.Extent (aka. a bookmark) in the DataGrid is the 0 index value.
///
///
/// The text of the Title for the Bookmark can be controlled via the
/// Title Property in XAML or code-behind.
///
///
/// Controlling the input text for the TextBox that provides a name for the Map.Extent is done via client
/// interaction. Developers can programmatically assign a text value by modifying the sub-component
/// AddBookmarkName TextBox of the Bookmark Control using a custom Control Template.
///
///
/// Controlling the behavior and appearance of the + button to add a named Map.Extent (aka. a bookmark)
/// to the DataGrid can be programmatically controlled by modifying the sub-component AddBookmark Button
/// of the Bookmark Control using a custom Control Template.
///
///
/// Controlling the behavior and appearance of the DataGrid that contains the ObservableCollection of named
/// Map.Extent (aka. a bookmark) values can be programmatically controlled by modifying the sub-component
/// BookmarkList DataGrid of the Bookmark Control using a custom Control Template.
///
///
/// Controlling the behavior and appearance of the Clear button to remove all named Map.Extent (aka. a bookmark)
/// values from the DataGrid can be programmatically controlled by modifying the sub-component
/// ClearBookmarks Button of the Bookmark Control using a custom Control Template.
///
///
///
///
/// How to use:
///
///
/// This example provides a default Bookmark Control that is bound to a Map Control to experiment with its
/// functionality. Additionally, there are several Buttons that can be clicked to see how some of the behavior
/// and appearance of the Bookmark Control can be modified via the code-behind.
///
///
/// The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate
/// the functionality.
///
///
/// The following screen shot corresponds to the code example in this page.
///
///
///
///
///
/// <Grid x:Name="LayoutRoot">
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="70" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="626"
/// TextWrapping="Wrap" Margin="2,9,0,0"
/// Text="This example provides a default Bookmark Control that is bound to a Map Control to
/// experiment with its functionality. Additionally, there are several Buttons that can be
/// clicked to see how some of the behavior and appearance of the Bookmark Control can be
/// modified via the code-behind." />
///
/// <!-- Add a Map Control. -->
/// <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,85,0,0" Name="Map1"
/// VerticalAlignment="Top" Height="360" Width="401" >
///
/// <!-- Add a default ArcGISTiledMapServiceLayer for visual display in the Map. -->
/// <esri:ArcGISTiledMapServiceLayer ID="PhysicalTiledLayer"
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
/// </esri:Map>
///
/// <!--
/// Add a default Bookmark Control. The Bookmark.Map Property has been bound to the Map Control.
/// The Bookmark.IsolatedStorage Property have been set to False (the default is True) to clear
/// out the MapBookmark items each time the application runs. -->
/// <esri:Bookmark HorizontalAlignment="Left" Margin="419,278,0,0" Name="Bookmark1"
/// VerticalAlignment="Top" Width="208" Height="168"
/// Map="{Binding ElementName=Map1}" UseIsolatedStorage="False"/>
///
/// <!--
/// A Button with code-behind to show adding a MapBookmark to the Bookmark Control. This version
/// uses an Envelope.Extent via String X,Y coordinate pairs to populate the MapBookmark.Extent.
/// -->
/// <Button Content="AddBookmark Method" HorizontalAlignment="Left" Margin="420,86,0,0"
/// Name="Button_AddBookmark" VerticalAlignment="Top" Width="209" Click="Button_AddBookmark_Click"/>
///
/// <!--
/// A Button with code-behind to show adding a MapBookmark to the Bookmark Control. This version
/// uses the current Map.Extent for the MapBookmark.Extent value.
/// -->
/// <Button Content="AddBookmark v2 Method" Height="23" HorizontalAlignment="Left" Margin="421,115,0,0"
/// Name="Button_AddBookmarkv2" VerticalAlignment="Top" Width="208" Click="Button_AddBookmarkv2_Click"/>
///
/// <!-- A button with code-behind to clear out all items in the Bookmark Control. -->
/// <Button Content="ClearBookmarks Method" Height="23" HorizontalAlignment="Left" Margin="421,144,0,0"
/// Name="Button_ClearBookmarks" VerticalAlignment="Top" Width="209" Click="Button_ClearBookmarks_Click"/>
///
/// <!-- A button with code-behind to clear out just the first MapBookmark item in the Bookmark Control. -->
/// <Button Content="DeleteBookmarkAt Method" Height="23" HorizontalAlignment="Left" Margin="420,173,0,0"
/// Name="Button_DeleteBookmarkAt" VerticalAlignment="Top" Width="209" Click="Button_DeleteBookmarkAt_Click" />
///
/// <!--
/// A button with code-behind to display all of the MapBookmark.Name and MapBookmark.Extent values in
/// the Bookmark Control via a MessageBox. -->
/// <Button Content="Bookmarks Property" Height="23" HorizontalAlignment="Left" Margin="420,202,0,0"
/// Name="Button_Bookmarks" VerticalAlignment="Top" Width="209" Click="Button_Bookmarks_Click"/>
///
/// <!-- A button with code-behind to change the default Title of the Bookmark Control. -->
/// <Button Content="Title Property" Height="23" HorizontalAlignment="Left" Margin="420,231,0,0"
/// Name="Button_Title" VerticalAlignment="Top" Width="209" Click="Button_Title_Click"/>
/// </Grid>
///
///
/// private void Button_AddBookmark_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function add a new named Map.Extent (aka. a bookmark) to the ObservableCollection<MapBookmark>.
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtent = new ESRI.ArcGIS.Client.Geometry.Envelope(-1837672.03060728, 3202886.78616195, 4708662.7690822, 9079895.58388817);
/// Bookmark1.AddBookmark("Europe", myExtent);
/// }
///
/// private void Button_AddBookmarkv2_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // An alternate method of adding a named MapExtent (aka. a bookmark) to the ObservableCollection<MapBookmark>.
/// Bookmark1.AddBookmark("A custom location", Map1.Extent);
/// }
///
/// private void Button_ClearBookmarks_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This Clears ALL of the Bookmarks. Same functionality as the 'Clear' button in the default GUI for the control.
/// Bookmark1.ClearBookmarks();
/// }
///
/// private void Button_DeleteBookmarkAt_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function deletes the first occurrence of a MapBookmark from the Bookmark.Control.
///
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> myBookmarks = null;
/// myBookmarks = Bookmark1.Bookmarks;
/// if (myBookmarks.Count > 0)
/// {
/// // Delete the top most bookmark
/// Bookmark1.DeleteBookmarkAt(0);
/// }
/// }
///
/// private void Button_Bookmarks_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function loops through all of the MapBookmark items in the Bookmark.Bookmarks
/// // ObservableCollection<MapBookmark> to display the MapBookmark.Name and MapBookmark.Extent.
///
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> myBookmarks = null;
/// myBookmarks = Bookmark1.Bookmarks;
///
/// foreach (ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark oneMapBookmark in myBookmarks)
/// {
/// MessageBox.Show("The MapBookmark: " + oneMapBookmark.Name + Environment.NewLine + "Has the Extent: " + oneMapBookmark.Extent.ToString());
/// }
/// }
///
/// private void Button_Title_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // Modify the default title of the Bookmark Control.
/// Bookmark1.Title = "My Custom Title";
/// }
///
///
/// Private Sub Button_AddBookmark_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function add a new named Map.Extent (aka. a bookmark) to the ObservableCollection(Of MapBookmark).
/// Dim myExtent As New ESRI.ArcGIS.Client.Geometry.Envelope(-1837672.03060728, 3202886.78616195, 4708662.7690822, 9079895.58388817)
/// Bookmark1.AddBookmark("Europe", myExtent)
///
/// End Sub
///
/// Private Sub Button_AddBookmarkv2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' An alternate method of adding a named MapExtent (aka. a bookmark) to the ObservableCollection(Of MapBookmark).
/// Bookmark1.AddBookmark("A custom location", Map1.Extent)
///
/// End Sub
///
/// Private Sub Button_ClearBookmarks_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This Clears ALL of the Bookmarks. Same functionality as the 'Clear' button in the default GUI for the control.
/// Bookmark1.ClearBookmarks()
///
/// End Sub
///
/// Private Sub Button_DeleteBookmarkAt_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function deletes the first occurrence of a MapBookmark from the Bookmark.Control.
///
/// Dim myBookmarks As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
/// myBookmarks = Bookmark1.Bookmarks
/// If myBookmarks.Count > 0 Then
///
/// ' Delete the top most bookmark
/// Bookmark1.DeleteBookmarkAt(0)
///
/// End If
///
/// End Sub
///
/// Private Sub Button_Bookmarks_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function loops through all of the MapBookmark items in the Bookmark.Bookmarks
/// ' ObservableCollection(Of MapBookmark) to display the MapBookmark.Name and MapBookmark.Extent.
///
/// Dim myBookmarks As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
/// myBookmarks = Bookmark1.Bookmarks
///
/// For Each oneMapBookmark As ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark In myBookmarks
/// MessageBox.Show("The MapBookmark: " + oneMapBookmark.Name + vbCrLf +
/// "Has the Extent: " + oneMapBookmark.Extent.ToString)
/// Next
///
/// End Sub
///
/// Private Sub Button_Title_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' Modify the default title of the Bookmark Control.
/// Bookmark1.Title = "My Custom Title"
///
/// End Sub
///
///
[TemplatePart(Name = "AddBookmark", Type = typeof(Button))]
[TemplatePart(Name = "ClearBookmarks", Type = typeof(Button))]
[TemplatePart(Name = "BookmarkList", Type = typeof(DataGrid))]
[TemplatePart(Name = "AddBookmarkName", Type = typeof(TextBox))]
public class Bookmark : Control
{
#if !SILVERLIGHT
private int current_index = -1;
private int previous_index = -1;
#endif
private bool is_editing = false;
///
/// Bookmark class for storing named extents
///
public class MapBookmark
{
///
/// Gets or sets the name.
///
/// The name.
public string Name { get; set; }
///
/// Gets or sets the extent.
///
/// The extent.
public ESRI.ArcGIS.Client.Geometry.Envelope Extent { get; set; }
///
/// Returns a that represents the current .
///
///
/// A that represents the current .
///
public override string ToString()
{
return Name;
}
}
private const string isolatedStorageKey = "ESRI.ArcGIS.Client.Toolkit.BookMarks";
private string Key
{
get { return isolatedStorageKey + "_" + this.Name; }
}
///
/// Gets the ObservableCollection containing
/// Bookmark.MapBookmark objects that are
/// displayed in the DataGrid sub-component of the Bookmark Control.
///
///
///
/// The Bookmark.Bookmarks Property gets a ReadOnly ObservableCollection(Of
/// Bookmark.MapBookmark) object. This
/// object is used to store the named Map.Extent pairs (aka. bookmarks) that are displayed in the DataGrid
/// sub-component of the Bookmark Control. When a Bookmark Control is created, the ObservableCollection
/// (Of MapBookmark) object is also created. Although the MapBookmark.Bookmarks Property is ReadOnly, meaning
/// you can only get the ObservableCollection (Of MapBookmark) object, you can use the regular
/// ObservableCollection Members to like:
/// Add,
/// Clear,
/// Remove,
/// etc. to define how the Bookmark Control behaves. NOTE: You cannot create an new instance of the
/// ObservableCollection (Of MapBookmark) object and set it to the Bookmark.Bookmarks Property, use the
/// ObservableCollection.Add Property instead.
///
///
/// You can also control the behavior of the ObservableCollection (Of MapBookmark) object by using the
/// AddBookmark,
/// ClearBookmarks, and
/// DeleteBookmarkAt Methods.
///
///
/// By default the
/// ESRI.ArcGIS.Client.Toolkit.Bookmark.UseIsolatedStorage value
/// equals True. This means that the application will remember from one session to another the named Map.Extent
/// (aka. a bookmark) values previously entered. If the Bookmark.UseIsolatedStorage is set to False, the next
/// time a user begins another client session of the application the named Map.Extent (aka. a bookmark) settings
/// will be lost. Note: There is only one IsolatedStorage container per application. This may have
/// implications if you have multiple Maps, each with their own set of bookmarks. This means you may need to make
/// use of the Bookmark.Bookmarks Property to persist across the various Maps.
///
///
///
///
/// How to use:
///
///
/// Click the different RadioButtons to change the items in the Bookmark Control. Then click the various
/// Bookmark.MapBookmark items in the Bookmark Control to zoom to the different Extents.
///
///
/// The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate
/// the functionality.
///
///
/// The following screen shot corresponds to the code example in this page.
///
///
///
///
///
/// <Grid x:Name="LayoutRoot">
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="52" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="626"
/// TextWrapping="Wrap" Margin="2,9,0,0"
/// Text="Click the different RadioButtons to change the items in the Bookmark Control. Then click the
/// various Bookmark.MapBookmark items in the Bookmark Control to zoom to the different Extents." />
///
/// <!-- Add a Map Control. -->
/// <esri:Map Background="White" HorizontalAlignment="Left" Margin="12,85,0,0" Name="Map1"
/// VerticalAlignment="Top" Height="360" Width="401" >
///
/// <!-- Add an ArcGISTiledMapServiceLayer for a data source. -->
/// <esri:ArcGISTiledMapServiceLayer ID="PhysicalTiledLayer"
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
/// </esri:Map>
///
/// <!-- Add a Bookmark Control. Bind the Bookmark.Map Property to the Map Control. -->
/// <esri:Bookmark HorizontalAlignment="Left" Margin="426,85,0,0" Name="Bookmark1"
/// VerticalAlignment="Top" Width="179"
/// Map="{Binding ElementName=Map1}"/>
///
/// <!--
/// Add a RadioButton that will correspond to State level predefined Map.Extents. The Click Event is
/// Wired-up for use with the code-behind. Note how it uses the same Event handler as the other
/// Radio Buttons. It is the use of the RadioButton.Tag Property that will help the code-behind
/// functions know which RadioButton was chosen.
/// -->
/// <RadioButton Content="State (FL and GA)" Height="16" HorizontalAlignment="Left" Margin="12,67,0,0"
/// Name="RadioButton_State" VerticalAlignment="Top" Click="RadioButtons"
/// Tag="State"/>
///
/// <!--
/// Add a RadioButton that will correspond to local level predefined Map.Extents. The Click Event is
/// Wired-up for use with the code-behind. Note how it uses the same Event handler as the other
/// Radio Buttons. It is the use of the RadioButton.Tag Property that will help the code-behind
/// functions know which RadioButton was chosen.
/// -->
/// <RadioButton Content="Florida (local)" Height="16" HorizontalAlignment="Left" Margin="154,67,0,0"
/// Name="RadioButton_Local_FL" VerticalAlignment="Top" Click="RadioButtons"
/// Tag="FL"/>
///
/// <!--
/// Add a RadioButton that will correspond to local level predefined Map.Extents. The Click Event is
/// Wired-up for use with the code-behind. Note how it uses the same Event handler as the other
/// Radio Buttons. It is the use of the RadioButton.Tag Property that will help the code-behind
/// functions know which RadioButton was chosen.
/// -->
/// <RadioButton Content="Georgia (local)" Height="16" HorizontalAlignment="Left" Margin="288,67,0,0"
/// Name="RadioButton_Local_GA" VerticalAlignment="Top" Click="RadioButtons"
/// Tag="GA"/>
///
/// </Grid>
///
///
/// private void RadioButtons(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function serves as the Click Event handler for the three RadioButtons. Get the .Tag
/// // Property from the RadioButton to construct an ObservableCollecton of MapBookmark objects.
/// // Then add the MapBookmark items to the Bookmark Control.
///
/// // Get the RadioButton from the sender.
/// RadioButton theRadioButton = (RadioButton)sender;
///
/// // Get the String identifying which RadioButton we have from the RadioButton.Tag Property.
/// string theTag = (string)theRadioButton.Tag;
///
/// // Get the ObservableCollection<Of MapBookmark> object based upon which RadioButton the user chose.
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> myObservableCollectionOfMapBookmark = null;
/// myObservableCollectionOfMapBookmark = GenerateObservableCollectionOfMapBookmark(theTag);
///
/// // Clear out any existing MapBookmark objects from the Bookmark Control.
/// Bookmark1.ClearBookmarks();
///
/// // Loop through the ObservableCollection<MapBookmark> object and add each MapBookmark to
/// // the Bookmark Control using the .Bookmarks Property.
/// foreach (ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark oneMapBookmark in myObservableCollectionOfMapBookmark)
/// {
/// // The Bookmark.Bookmarks Property returns a ReadOnly ObservableCollection<MapBookmark>
/// // object. So to get items in the ObservableCollection, use the Add Property.
/// Bookmark1.Bookmarks.Add(oneMapBookmark);
///
/// // This could be an alternative way to add a MapBookmark to the ObservableCollection!
/// // Bookmark1.AddBookmark(oneMapBookmark.Name, oneMapBookmark.Extent);
/// }
///
/// // NOTE: Because the Bookmark.Bookmarks Property returns a Read Only
/// // ObservableCollection<MapBookmark>, you CANNOT do this:
/// // Bookmark1.Bookmarks = myObservableCollectionOfMapBookmark;
/// }
///
/// public Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> GenerateObservableCollectionOfMapBookmark(string theTag)
/// {
/// // This the main function that generates the correct set of MapBookmark items to be added to the
/// // Bookmark Control. Depending on which RadioButton the user chose will determine what gets added to
/// // the ObservableCollection<MapBookmark>.
///
/// // Create a new instance of the ObservableCollection<MapBookmark>.
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> theBookmarks = new Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark>();
///
/// if (theTag == "State")
/// {
/// // Generate MapBookmark's for a State level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Florida and Georgia", new ESRI.ArcGIS.Client.Geometry.Envelope(-10126037, 2750924, -8487426, 4221996)));
/// theBookmarks.Add(MakeMapBookmark("Florida", new ESRI.ArcGIS.Client.Geometry.Envelope(-9808676, 2779124, -8812475, 3673469)));
/// theBookmarks.Add(MakeMapBookmark("Georgia", new ESRI.ArcGIS.Client.Geometry.Envelope(-9633752, 3534963, -8898290, 4195229)));
/// }
/// else if (theTag == "FL")
/// {
/// // Generate MapBookmark's for a local level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Jacksonville", new ESRI.ArcGIS.Client.Geometry.Envelope(-9105796, 3532477, -9075555, 3559626)));
/// theBookmarks.Add(MakeMapBookmark("Miami", new ESRI.ArcGIS.Client.Geometry.Envelope(-8936736, 2965084, -8918792, 2981193)));
/// theBookmarks.Add(MakeMapBookmark("Tampa", new ESRI.ArcGIS.Client.Geometry.Envelope(-9194994, 3225279, -9165864, 3251430)));
/// }
/// else if (theTag == "GA")
/// {
/// // Generate MapBookmark's for a local level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Atlanta", new ESRI.ArcGIS.Client.Geometry.Envelope(-9421000, 3975108, -9367812, 4022858)));
/// theBookmarks.Add(MakeMapBookmark("Columbus", new ESRI.ArcGIS.Client.Geometry.Envelope(-9464616, 3820843, -9455555, 3828978)));
/// theBookmarks.Add(MakeMapBookmark("Savannah", new ESRI.ArcGIS.Client.Geometry.Envelope(-9043472, 3757220, -9013688, 3783958)));
/// }
///
/// // Return the ObservableCollection<MapBookmark> to the caller.
/// return theBookmarks;
/// }
///
/// public ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark MakeMapBookmark(string aName, ESRI.ArcGIS.Client.Geometry.Envelope anExtent)
/// {
/// // A helper function to create a single MapBookmark based upon an input Name and Extent.
/// ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark aMapBookmark = new ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark();
/// aMapBookmark.Name = aName;
/// aMapBookmark.Extent = anExtent;
///
/// // Return the MapBookmark to the caller.
/// return aMapBookmark;
/// }
///
///
/// Private Sub RadioButtons(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function serves as the Click Event handler for the three RadioButtons. Get the .Tag
/// ' Property from the RadioButton to construct an ObservableCollecton of MapBookmark objects.
/// ' Then add the MapBookmark items to the Bookmark Control.
///
/// ' Get the RadioButton from the sender.
/// Dim theRadioButton As RadioButton = sender
///
/// ' Get the String identifying which RadioButton we have from the RadioButton.Tag Property.
/// Dim theTag As String = theRadioButton.Tag
///
/// ' Get the ObservableCollection(Of MapBookmark) object based upon which RadioButton the user chose.
/// Dim myObservableCollectionOfMapBookmark As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
/// myObservableCollectionOfMapBookmark = GenerateObservableCollectionOfMapBookmark(theTag)
///
/// ' Clear out any existing MapBookmark objects from the Bookmark Control.
/// Bookmark1.ClearBookmarks()
///
/// ' Loop through the ObservableCollection(Of MapBookmark) object and add each MapBookmark to
/// ' the Bookmark Control using the .Bookmarks Property.
/// For Each oneMapBookmark As ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark In myObservableCollectionOfMapBookmark
///
/// ' The Bookmark.Bookmarks Property returns a ReadOnly ObservableCollection(Of MapBookmark)
/// ' object. So to get items in the ObservableCollection, use the Add Property.
/// Bookmark1.Bookmarks.Add(oneMapBookmark)
///
/// ' This could be an alternative way to add a MapBookmark to the ObservableCollection!
/// 'Bookmark1.AddBookmark(oneMapBookmark.Name, oneMapBookmark.Extent)
///
/// Next
///
/// ' NOTE: Because the Bookmark.Bookmarks Property returns a Read Only
/// ' ObservableCollection(Of MapBookmark), you CANNOT do this:
/// 'Bookmark1.Bookmarks = myObservableCollectionOfMapBookmark
///
/// End Sub
///
/// Public Function GenerateObservableCollectionOfMapBookmark(ByVal theTag As String) As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
///
/// ' This the main function that generates the correct set of MapBookmark items to be added to the
/// ' Bookmark Control. Depending on which RadioButton the user chose will determine what gets added to
/// ' the ObservableCollection(Of MapBookmark).
///
/// ' Create a new instance of the ObservableCollection(Of MapBookmark).
/// Dim theBookmarks As New Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
///
/// If theTag = "State" Then
///
/// ' Generate MapBookmark's for a State level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Florida and Georgia", New ESRI.ArcGIS.Client.Geometry.Envelope(-10126037, 2750924, -8487426, 4221996)))
/// theBookmarks.Add(MakeMapBookmark("Florida", New ESRI.ArcGIS.Client.Geometry.Envelope(-9808676, 2779124, -8812475, 3673469)))
/// theBookmarks.Add(MakeMapBookmark("Georgia", New ESRI.ArcGIS.Client.Geometry.Envelope(-9633752, 3534963, -8898290, 4195229)))
///
/// ElseIf theTag = "FL" Then
///
/// ' Generate MapBookmark's for a local level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Jacksonville", New ESRI.ArcGIS.Client.Geometry.Envelope(-9105796, 3532477, -9075555, 3559626)))
/// theBookmarks.Add(MakeMapBookmark("Miami", New ESRI.ArcGIS.Client.Geometry.Envelope(-8936736, 2965084, -8918792, 2981193)))
/// theBookmarks.Add(MakeMapBookmark("Tampa", New ESRI.ArcGIS.Client.Geometry.Envelope(-9194994, 3225279, -9165864, 3251430)))
///
/// ElseIf theTag = "GA" Then
///
/// ' Generate MapBookmark's for a local level of viewing.
/// theBookmarks.Add(MakeMapBookmark("Atlanta", New ESRI.ArcGIS.Client.Geometry.Envelope(-9421000, 3975108, -9367812, 4022858)))
/// theBookmarks.Add(MakeMapBookmark("Columbus", New ESRI.ArcGIS.Client.Geometry.Envelope(-9464616, 3820843, -9455555, 3828978)))
/// theBookmarks.Add(MakeMapBookmark("Savannah", New ESRI.ArcGIS.Client.Geometry.Envelope(-9043472, 3757220, -9013688, 3783958)))
///
/// End If
///
/// ' Return the ObservableCollection(Of MapBookmark) to the caller.
/// Return theBookmarks
///
/// End Function
///
/// Public Function MakeMapBookmark(ByVal aName As String, ByVal anExtent As ESRI.ArcGIS.Client.Geometry.Envelope) As ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark
///
/// ' A helper function to create a single MapBookmark based upon an input Name and Extent.
/// Dim aMapBookmark As New ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark
/// aMapBookmark.Name = aName
/// aMapBookmark.Extent = anExtent
///
/// ' Return the MapBookmark to the caller.
/// Return aMapBookmark
///
/// End Function
///
///
public System.Collections.ObjectModel.ObservableCollection Bookmarks { get; private set; }
///
/// Initializes a new instance of the class.
///
public Bookmark()
{
Bookmarks = new System.Collections.ObjectModel.ObservableCollection();
#if SILVERLIGHT
DefaultStyleKey = typeof(Bookmark);
UseIsolatedStorage = true;
this.Loaded += new RoutedEventHandler(Bookmark_Loaded);
#endif
}
///
/// Static initialization for the control.
///
static Bookmark()
{
#if !SILVERLIGHT
DefaultStyleKeyProperty.OverrideMetadata(typeof(Bookmark), new FrameworkPropertyMetadata(typeof(Bookmark)));
#endif
}
#if SILVERLIGHT
private void Bookmark_Loaded(object sender, RoutedEventArgs e)
{
LoadBookmarks();
}
private void SaveBookmarks()
{
if (DesignerProperties.GetIsInDesignMode(this))
return;
try
{
if (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Contains(Key))
System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Remove(Key);
if (UseIsolatedStorage && Bookmarks != null && Bookmarks.Count > 0)
{
System.Collections.ObjectModel.ObservableCollection bookmarkClone = new System.Collections.ObjectModel.ObservableCollection();
foreach (MapBookmark item in Bookmarks)
bookmarkClone.Add(item);
System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Add(Key, bookmarkClone);
}
System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Save();
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(Properties.Resources.Bookmark_SaveFailed + ex.Message);
}
}
private void LoadBookmarks()
{
if (UseIsolatedStorage && !DesignerProperties.GetIsInDesignMode(this))
{
if (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Contains(Key))
{
System.Collections.ObjectModel.ObservableCollection storedMarks =
System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings[Key] as System.Collections.ObjectModel.ObservableCollection;
Bookmarks.Clear();
if (storedMarks != null)
foreach (MapBookmark marks in storedMarks)
Bookmarks.Add(marks);
}
}
}
#endif
TextBox AddBookmarkName;
Button AddBookmarkButton;
DataGrid BookmarkList;
///
/// When overridden in a derived class, is invoked whenever application code
/// or internal processes (such as a rebuilding layout pass) call
/// .
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AddBookmarkName = GetTemplateChild("AddBookmarkName") as TextBox;
AddBookmarkButton = GetTemplateChild("AddBookmark") as Button;
BookmarkList = GetTemplateChild("BookmarkList") as DataGrid;
if(AddBookmarkButton!=null)
AddBookmarkButton.Click += AddBookmarkButton_Click;
if (BookmarkList != null)
{
#if !SILVERLIGHT
BookmarkList.CanUserAddRows = false;
#endif
BookmarkList.ItemsSource = Bookmarks;
BookmarkList.SelectionChanged += BookmarkList_SelectionChanged;
BookmarkList.BeginningEdit += BookmarkList_BeginningEdit;
BookmarkList.CellEditEnding += BookmarkList_CellEditEnding;
}
Button ClearBookmarksButton = GetTemplateChild("ClearBookmarks") as Button;
if (ClearBookmarksButton != null)
{
ClearBookmarksButton.Click += (o, e) => { ClearBookmarks(); };
}
}
void BookmarkList_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
is_editing = false;
}
void BookmarkList_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
{
is_editing = true;
}
private void BookmarkList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
#if !SILVERLIGHT
current_index = BookmarkList.SelectedIndex;
#endif
MapBookmark bookmark = BookmarkList.SelectedItem as MapBookmark;
if (bookmark!=null && Map != null && !Double.IsNaN(Map.Resolution))
{
Map.ZoomTo(bookmark.Extent);
}
}
private void AddBookmarkButton_Click(object sender, RoutedEventArgs e)
{
if (Map == null) return;
string name = null;
if (AddBookmarkName != null)
name = AddBookmarkName.Text;
AddBookmark(name, Map.Extent);
}
///
/// Identifies the dependency property.
///
public static readonly DependencyProperty MapProperty = DependencyProperty.Register("Map", typeof(Map), typeof(Bookmark), new PropertyMetadata(OnMapPropertyChanged));
private static void OnMapPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Bookmark bookmark = d as Bookmark;
Map oldValue = e.OldValue as Map;
Map newValue = e.NewValue as Map;
if (oldValue != null)
oldValue.ExtentChanged -= bookmark.map_ExtentChanged;
if (newValue != null)
newValue.ExtentChanged += bookmark.map_ExtentChanged;
}
///
/// Gets or sets the map that the is buddied to.
///
public Map Map
{
get { return GetValue(MapProperty) as Map; }
set { SetValue(MapProperty, value); }
}
private void map_ExtentChanged(object sender, ExtentEventArgs args)
{
#if !SILVERLIGHT
// the data grid in wpf requires two mouse clicks to enter edit mode.
// the silverlight data grid only requires one mouse click to enter edit mode.
// current index and previous index manage the history for the wpf version
// so the index is not lost after first click.
if (current_index != -1 && current_index == previous_index || is_editing)
{
current_index = -1;
return;
}
previous_index = current_index;
#else
if(is_editing) return;
#endif
if (BookmarkList != null)
BookmarkList.SelectedIndex = -1;
}
///
/// Adds a named Map.Extent (aka. a bookmark) into the DataGrid sub-component of the Bookmark Control.
///
///
///
/// The AddBookmark Method adds a named Map.Extent (aka. a bookmark) into the
/// ObservableCollection(Of Bookmark.MapBookmark) object. The ObservableCollection(Of Bookmark.MapBookmark)
/// object is internally bound to the DataGrid sub-component in the
/// Bookmark Control. Use the
/// Bookmark.Bookmarks Property to obtain the
/// ObservableCollection(Of Bookmark.MapBookmark) object.
///
///
/// There are two input parameters for the AddBookmark Method: name and extent.The name
/// is the human readable string that defines a geographic extent on the Map. The extent is the
/// Map.Extent that corresponds to item name in the
/// ObservableCollection.
///
///
/// The functionality of the AddBookmark Method is comparable to when a user of a client application types a
/// string into the Textbox sub-component of the Bookmark Control and clicks the + button, causing the
/// named Map.Extent (aka. a bookmark) to appear in the DataGrid. It should be noted that the AddBookmark
/// Method IS NOT the Event for the + button of the Bookmark Control. To change the core behavior of
/// any of the sub-components and their appearance of the Bookmark Control (including the + button),
/// developers must modify the Control Template in XAML and the associated code-behind file. The easiest way
/// to modify the UI sub-components is using Microsoft Expression Blend. Then developers can delete/modify
/// existing or add new sub-components in Visual Studio to create a truly customized experience. A general
/// approach to customizing a Control Template is discussed in the ESRI blog entitled:
/// Use control templates to customize the look and feel of ArcGIS controls.
/// An example of modifying the Control Template of the Bookmark control to provide an alternate set of
/// functionality that automatically populates several named Map.Extent (aka. a bookmark) values via the
/// AddBookmark Method is provided in the code example section of this document.
///
///
///
///
/// How to use:
///
///
/// This example code shows disabling some of the features of the Bookmark Control to create a kiosk type of
/// application. Users are not allowed to make any editable changes to the Bookmark Control. To use: Click the
/// various preset bookmarks to see the Four Corners area of the United States.
///
///
/// The following screen shot corresponds to the code example in this page.
///
///
///
///
///
/// <Grid x:Name="LayoutRoot" Background="White">
///
/// <!--
/// Use the Resources section to hold a Style for setting the appearance and behavior of the Bookmark Control.
/// Don't forget to add following XAML Namespace definitions to the correct location in your code:
/// xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
/// xmlns:esri="http://schemas.esri.com/arcgis/client/2009"
/// -->
/// <Grid.Resources>
///
/// <!--
/// The majority of the XAML that defines the ControlTemplate for the Bookmark Control was obtained
/// by using Microsoft Blend. See the blog post entitled: 'Use control templates to customize the
/// look and feel of ArcGIS controls' at the following Url for general How-To background:
/// http://blogs.esri.com/Dev/blogs/silverlightwpf/archive/2010/05/20/Use-control-templates-to-customize-the-look-and-feel-of-ArcGIS-controls.aspx
/// -->
/// <Style x:Key="BookmarkStyle1" TargetType="esri:Bookmark">
/// <Setter Property="MaxHeight" Value="200"/>
/// <Setter Property="Width" Value="120"/>
/// <Setter Property="Background" Value="#99000000"/>
///
/// <!-- The Title.Value was modified. -->
/// <Setter Property="Title" Value="Four Corners Kiosk"/>
///
/// <Setter Property="BorderThickness" Value="1"/>
/// <Setter Property="BorderBrush" Value="White"/>
/// <Setter Property="Template">
/// <Setter.Value>
/// <ControlTemplate TargetType="esri:Bookmark">
/// <Grid Background="Yellow">
/// <Grid.RowDefinitions>
/// <RowDefinition Height="25"/>
///
/// <!-- Changed the Height for better visual appeal. -->
/// <RowDefinition Height="1"/>
///
/// <RowDefinition Height="*"/>
/// <RowDefinition Height="25"/>
/// </Grid.RowDefinitions>
/// <Border BorderBrush="{TemplateBinding BorderBrush}"
/// BorderThickness="{TemplateBinding BorderThickness}"
/// Background="{TemplateBinding Background}"
/// CornerRadius="5"
/// Grid.RowSpan="4"/>
/// <TextBlock Foreground="Black" FontWeight="Bold" FontSize="12"
/// FontFamily="Verdana" Margin="5,5,5,0"
/// Grid.Row="0" Text="{TemplateBinding Title}"/>
///
/// <!-- Comment out the entire section that allows users to add bookmarks. Since
/// this is a Kiosk Application, we do not want users to make any changes.
/// -->
/// <!--
/// <Grid Margin="5,0,5,0" Grid.Row="1">
/// <Grid.ColumnDefinitions>
/// <ColumnDefinition Width="*"/>
/// <ColumnDefinition Width="30"/>
/// </Grid.ColumnDefinitions>
/// <TextBox x:Name="AddBookmarkName" Grid.Column="0" Width="200"/>
/// <Button x:Name="AddBookmark" Content="+" Grid.Column="1" />
/// </Grid>
/// -->
///
/// <!-- Add the IsReadOnly Attribute to disable the user from editing the bookmark names. -->
/// <sdk:DataGrid x:Name="BookmarkList" AutoGenerateColumns="False" CanUserResizeColumns="False"
/// CanUserReorderColumns="False" HeadersVisibility="None" Margin="5,0,5,0"
/// Grid.Row="2" RowHeight="16" RowDetailsVisibilityMode="Collapsed"
/// TabNavigation="Local" Visibility="Visible" IsReadOnly="True" >
/// <sdk:DataGrid.Columns>
/// <sdk:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" Foreground="Black"
/// FontSize="10" FontFamily="Times" Header="Bookmark"
/// IsReadOnly="False" Width="{TemplateBinding Width}"/>
/// </sdk:DataGrid.Columns>
/// </sdk:DataGrid>
///
/// <!-- Comment out the entire section that allows users to delete bookmarks. Since
/// this is a Kiosk Application, we do not want users to make any changes.
/// -->
/// <!--
/// <Grid Margin="5,0,5,5" Grid.Row="3">
/// <Grid.ColumnDefinitions>
/// <ColumnDefinition Width="*"/>
/// <ColumnDefinition Width="*"/>
/// </Grid.ColumnDefinitions>
/// <Button x:Name="ClearBookmarks" Content="Clear All" Grid.Column="0"/>
/// </Grid>
/// -->
///
/// </Grid>
/// </ControlTemplate>
/// </Setter.Value>
/// </Setter>
/// </Style>
/// </Grid.Resources>
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="70" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="626"
/// TextWrapping="Wrap" Margin="2,9,0,0"
/// Text="This example code shows disabling some of the features of the Bookmark Control to create
/// a kiosk type of application. Users are not allowed to make any editable changes to the Bookmark
/// Control. To use: Click the various preset bookmarks to see the Four Corners area of the
/// United States." />
///
/// <!-- Add a Map Control to the application and define an intial Map.Extent to the Four Corners states. -->
/// <esri:Map x:Name="MyMap" Extent="-12948716, 3633316, -11207358, 5196630"
/// Background="White" HorizontalAlignment="Left" Margin="12,85,0,0"
/// VerticalAlignment="Top" Height="360" Width="401">
///
/// <!-- Add an ArcGISTiledMapServiceLayer for some quick data display. -->
/// <esri:ArcGISTiledMapServiceLayer
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
/// </esri:Map>
///
/// <!--
/// Add a Bookmark Control. It is important to provide an x:Name attribute so it can be referenced
/// in the code-behind. Define the Style of the Bookmark to use the Control Template that was generated
/// in Blend and modified here in Visual Studio. The Map Property uses the default two-way Binding to
/// associate the Bookmark Control with the Map Control. The Loaded Event handler was added so that in
/// the code-behind some predefined bookmarks could be added.
/// -->
/// <esri:Bookmark x:Name="MyBookmarks" Width="200" HorizontalAlignment="Right" VerticalAlignment="Top"
/// Margin="0,85,12,0" Background="#CC919191" BorderBrush="#FF92a8b3" Foreground="Black"
/// Style="{StaticResource BookmarkStyle1}"
/// Map="{Binding ElementName=MyMap}" Loaded="MyBookmarks_Loaded"/>
///
/// </Grid>
///
///
/// private void MyBookmarks_Loaded(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function clears out any existing bookmarks and added several new ones to provide predefined
/// // functionality for zooming around the Four Corners states of the United States.
///
/// // Clear out any existing bookmarks.
/// MyBookmarks.ClearBookmarks();
///
/// // Add bookmarks for the various areas of the Four Corners region of the United States.
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtentTheFourCorners = new ESRI.ArcGIS.Client.Geometry.Envelope(-12948716, 3633316, -11207358, 5196630);
/// MyBookmarks.AddBookmark("The Four Corners", myExtentTheFourCorners);
///
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtentArizona = new ESRI.ArcGIS.Client.Geometry.Envelope(-12921190, 3642001, -11973117, 4493139);
/// MyBookmarks.AddBookmark("Arizona", myExtentArizona);
///
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtentColorado = new ESRI.ArcGIS.Client.Geometry.Envelope(-12190630, 4330502, -11325307, 5107351);
/// MyBookmarks.AddBookmark("Colorado", myExtentColorado);
///
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtentNewMexico = new ESRI.ArcGIS.Client.Geometry.Envelope(-12289052, 3647640, -11371077, 4471758);
/// MyBookmarks.AddBookmark("New Mexico", myExtentNewMexico);
///
/// ESRI.ArcGIS.Client.Geometry.Envelope myExtentUtah = new ESRI.ArcGIS.Client.Geometry.Envelope(-12850560, 4409389, -11995243, 5177256);
/// MyBookmarks.AddBookmark("Utah", myExtentUtah);
/// }
///
///
/// Private Sub MyBookmarks_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function clears out any existing bookmarks and added several new ones to provide predefined
/// ' functionality for zooming around the Four Corners states of the United States.
///
/// ' Clear out any existing bookmarks.
/// MyBookmarks.ClearBookmarks()
///
/// ' Add bookmarks for the various areas of the Four Corners region of the United States.
/// Dim myExtentTheFourCorners As New ESRI.ArcGIS.Client.Geometry.Envelope(-12948716, 3633316, -11207358, 5196630)
/// MyBookmarks.AddBookmark("The Four Corners", myExtentTheFourCorners)
///
/// Dim myExtentArizona As New ESRI.ArcGIS.Client.Geometry.Envelope(-12921190, 3642001, -11973117, 4493139)
/// MyBookmarks.AddBookmark("Arizona", myExtentArizona)
///
/// Dim myExtentColorado As New ESRI.ArcGIS.Client.Geometry.Envelope(-12190630, 4330502, -11325307, 5107351)
/// MyBookmarks.AddBookmark("Colorado", myExtentColorado)
///
/// Dim myExtentNewMexico As New ESRI.ArcGIS.Client.Geometry.Envelope(-12289052, 3647640, -11371077, 4471758)
/// MyBookmarks.AddBookmark("New Mexico", myExtentNewMexico)
///
/// Dim myExtentUtah As New ESRI.ArcGIS.Client.Geometry.Envelope(-12850560, 4409389, -11995243, 5177256)
/// MyBookmarks.AddBookmark("Utah", myExtentUtah)
///
/// End Sub
///
///
/// Display name (aka. named Map.Extent or bookmark).
/// The Map.Extent of the bookmark.
public void AddBookmark(string name, ESRI.ArcGIS.Client.Geometry.Envelope extent)
{
name = name.Trim();
if (string.IsNullOrEmpty(name))
{
name = Properties.Resources.Bookmark_Name + (Bookmarks.Count + 1);
}
MapBookmark bookmark = new MapBookmark()
{
Name = name,
Extent = extent
};
Bookmarks.Add(bookmark);
BookmarkList.InvalidateMeasure();
if (BookmarkList != null && BookmarkList.Columns.Count>0)
BookmarkList.ScrollIntoView(bookmark, BookmarkList.Columns[0]);
#if SILVERLIGHT
SaveBookmarks();
#endif
}
///
/// Deletes a bookmark from the DataGrid sub-component of the Bookmark Control at a specified index.
///
///
///
/// The DeleteBookmark Method deletes a single Bookmark from the ObservableCollection(Of Bookmark.MapBookmark)
/// object. The ObservableCollection(Of Bookmark.MapBookmark) object is internally bound to the DataGrid
/// sub-component in the Bookmark Control. Use the
/// Bookmark.Bookmarks Property to obtain the
/// ObservableCollection(Of Bookmark.MapBookmark) object.
///
///
/// Unlike the Bookmark.AddBookmark Method
/// which takes a name and a Map.Extent as parameters to add items into the ObservableCollection,
/// the DeleteBookmark Method requires an Integer index value to remove an item from the
/// ObservableCollection. No Method exists as of the Silverlight/WPF/Windows Phone version 2.2 to remove an item
/// from the ObservableCollection by its name.
///
///
/// The top-most Bookmark listed in the DataGrid sub-component of the Bookmark Control is the zero (0) item index
/// value.
///
///
/// As of the Silverlight/WPF/Windows Phone version 2.2 there is no Property/Method on the Bookmark Control to
/// obtain the selected index value(s) of the DataGrid sub-component from client user interaction. However,
/// developers can change the core behavior of any of the sub-components and their appearance of the Bookmark
/// Control (including the obtaining selection index values of the DataGrid sub-component) by modifying the
/// Control Template in XAML and the associated code-behind file. The easiest way to modify the UI sub-components
/// is using Microsoft Expression Blend. Then developers can delete/modify existing or add new sub-components in
/// Visual Studio to create a truly customized experience. A general approach to customizing a Control Template
/// is discussed in the ESRI blog entitled:
/// Use control templates to customize the look and feel of ArcGIS controls.
/// An example of modifying the Control Template of the Bookmark control to obtain the selection index value
/// of the DataGrid sub-component in the Bookmark Control is provided in the code example section of this
/// document.
///
///
///
///
/// How to use:
///
///
/// Pan/Zoom to a desired Map.Extent then type in some text for the name of the Bookmark and click the Add button.
/// Repeat several times at other extents to create more Bookmarks. The 'Clear All' button removes all the
/// Bookmarks. The 'Clear Selected' button only removes the Bookmark for which is chosen in the DataGrid using
/// the DeleteBookmarkAt Method. The 'Add' button has the behavior of adding a named Map.Extent (aka. a bookmark)
/// to the DataGrid with the additionally functionality of clearing the TextBox once the 'Add' button has been
/// clicked.
///
///
/// The following screen shot corresponds to the code example in this page.
///
///
///
///
///
/// <Grid x:Name="LayoutRoot" Background="White">
///
/// <!--
/// Use the Resources section to hold a Style for setting the appearance and behavior of the Bookmark Control.
/// Don't forget to add following XAML Namespace definitions to the correct location in your code:
/// xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
/// xmlns:esri="http://schemas.esri.com/arcgis/client/2009"
/// -->
/// <Grid.Resources>
///
/// <!--
/// The majority of the XAML that defines the ControlTemplate for the Bookmark Control was obtained
/// by using Microsoft Blend. See the blog post entitled: 'Use control templates to customize the
/// look and feel of ArcGIS controls' at the following Url for general How-To background:
/// http://blogs.esri.com/Dev/blogs/silverlightwpf/archive/2010/05/20/Use-control-templates-to-customize-the-look-and-feel-of-ArcGIS-controls.aspx
/// -->
/// <Style x:Key="BookmarkStyle1" TargetType="esri:Bookmark">
/// <Setter Property="MaxHeight" Value="200"/>
/// <Setter Property="Width" Value="120"/>
/// <Setter Property="Background" Value="#99000000"/>
///
/// <!-- The Title.Value was modified. -->
/// <Setter Property="Title" Value="Custom Bookmarks"/>
///
/// <Setter Property="BorderThickness" Value="1"/>
/// <Setter Property="BorderBrush" Value="White"/>
/// <Setter Property="Template">
/// <Setter.Value>
/// <ControlTemplate TargetType="esri:Bookmark">
/// <Grid Background="Yellow">
/// <Grid.RowDefinitions>
/// <RowDefinition Height="25"/>
/// <RowDefinition Height="20"/>
/// <RowDefinition Height="*"/>
/// <RowDefinition Height="25"/>
/// </Grid.RowDefinitions>
/// <Border BorderBrush="{TemplateBinding BorderBrush}"
/// BorderThickness="{TemplateBinding BorderThickness}"
/// Background="{TemplateBinding Background}"
/// CornerRadius="5"
/// Grid.RowSpan="4"/>
/// <TextBlock Foreground="Black" FontWeight="Bold" FontSize="12"
/// FontFamily="Verdana" Margin="5,5,5,0"
/// Grid.Row="0" Text="{TemplateBinding Title}"/>
/// <Grid Margin="5,0,5,0" Grid.Row="1">
/// <Grid.ColumnDefinitions>
/// <ColumnDefinition Width="*"/>
/// <ColumnDefinition Width="30"/>
/// </Grid.ColumnDefinitions>
/// <TextBox x:Name="AddBookmarkName" Grid.Column="0" Width="200"/>
///
/// <!--
/// Comment out the default Button with its default behavior. We will out our own
/// button and wire-up our own functionality.
/// -->
/// <!-- <Button x:Name="AddBookmark" Content="+" Grid.Column="1" /> -->
///
/// <!--
/// This Button is new and has different functionality from the default + (i.e. AddBookmark)
/// Button provided with the Bookmark Control. The new Button will have a different
/// Content value and will automatically erase what was in the TextBox once a new
/// bookmark is added. Note that the Click Event is wired up.
/// -->
/// <Button x:Name="AddBookmarkNEW" Content="Add" Grid.Column="1" Click="AddBookmarkNEW_Click" />
///
/// </Grid>
///
/// <!--
/// Changed the default behavior of the DataGrid sub-component of the Bookmark Control.
/// In particular we added a SelectionChanged Event handler and changed the SelectionMode
/// to Single so that only one bookmark could be selected at a time for the
/// ClearSelectedBookmark Button to work appropriately.
/// -->
/// <sdk:DataGrid x:Name="BookmarkList" AutoGenerateColumns="False" CanUserResizeColumns="False"
/// CanUserReorderColumns="False" HeadersVisibility="None" Margin="5,0,5,0"
/// Grid.Row="2" RowHeight="16" RowDetailsVisibilityMode="Collapsed"
/// TabNavigation="Local" Visibility="Visible"
/// SelectionChanged="BookmarkList_SelectionChanged"
/// SelectionMode="Single">
///
/// <sdk:DataGrid.Columns>
/// <sdk:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" Foreground="Black"
/// FontSize="10" FontFamily="Times" Header="Bookmark"
/// IsReadOnly="False" Width="{TemplateBinding Width}"/>
/// </sdk:DataGrid.Columns>
/// </sdk:DataGrid>
/// <Grid Margin="5,0,5,5" Grid.Row="3">
/// <Grid.ColumnDefinitions>
/// <ColumnDefinition Width="*"/>
/// <ColumnDefinition Width="*"/>
/// </Grid.ColumnDefinitions>
///
/// <!-- Modified the default Content of the Button to be more explicit. -->
/// <Button x:Name="ClearBookmarks" Content="Clear All" Grid.Column="0"/>
///
/// <!--
/// This Button is new and adds the ability to Delete just the selected bookmark from
/// the DataGrid sub-control. Notice that the Click Event is wired up for use in the
/// code-behind.
/// -->
/// <Button x:Name="ClearSelectedBookmark" Content="Clear Selected" Grid.Column="1"
/// Click="ClearSelectedBookmark_Click"/>
///
/// </Grid>
/// </Grid>
/// </ControlTemplate>
/// </Setter.Value>
/// </Setter>
/// </Style>
/// </Grid.Resources>
///
/// <!-- Provide the instructions on how to use the sample code. -->
/// <TextBlock Height="70" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="626"
/// TextWrapping="Wrap" Margin="2,9,0,0"
/// Text="Pan/Zoom to a desired Map.Extent then type in some text for the name of the Bookmark and click
/// the Add button. Repeat several times at other extents to create more Bookmarks. The 'Clear All'
/// button removes all the Bookmarks. The 'Clear Selected' button only removes the Bookmark for
/// which is chosen in the DataGrid using the DeleteBookmarkAt Method. The ‘Add’ button has the
/// behavior of adding a named Map.Extent (aka. a bookmark) to the DataGrid with the additionally
/// functionality of clearing the TextBox once the ‘Add’ button has been clicked." />
///
/// <!-- Add a Map Control to the application and define an intial Map.Extent. -->
/// <esri:Map x:Name="MyMap" Extent="-15000000,2000000,-7000000,8000000"
/// Background="White" HorizontalAlignment="Left" Margin="12,85,0,0"
/// VerticalAlignment="Top" Height="360" Width="401">
///
/// <!-- Add an ArcGISTiledMapServiceLayer for some quick data display. -->
/// <esri:ArcGISTiledMapServiceLayer
/// Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
/// </esri:Map>
///
/// <!--
/// Add a Bookmark Control. It is important to provide an x:Name attribute so it can be referenced
/// in the code-behind. Define the Style of the Bookmark to use the Control Template that was generated
/// in Blend and modified here in Visual Studio. The Map Property uses the default two-way Binding to
/// associate the Bookmark Control with the Map Control.
/// -->
/// <esri:Bookmark x:Name="MyBookmarks" Width="200" HorizontalAlignment="Right" VerticalAlignment="Top"
/// Margin="0,85,12,0" Background="#CC919191" BorderBrush="#FF92a8b3" Foreground="Black"
/// Style="{StaticResource BookmarkStyle1}" Map="{Binding ElementName=MyMap}" />
///
/// </Grid>
///
///
/// // This is a Member (aka. Global) variable that will contain the currently selected index value
/// // for the DataGrid sub-component in the Bookmark Control.
/// public int _SelectedIndex = -1;
///
/// private void BookmarkList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
/// {
/// // This function obtains the index location of the last cell a user clicked in the DataGrid
/// // sub-component in the Bookmark Control. It stores that value in the Global variable _SelectedIndex.
///
/// // Note: There is a bug in the Bookmark.SelectionChanged Event where it always fires twice when a
/// // DataGrid cell is selected. The first time the Bookmark.SelectionChanged Event fires the correct
/// // DataGrid.SelectedIndex value is obtained but then the Event fires a second time and always
/// // set the DataGrid.SelectedIndex value to -1. So this code is a workaround.
///
/// // Get the DataGrid sub-component of the Bookmark Control.
/// DataGrid myDataGrid = (DataGrid)sender;
///
/// // Get the ObservableCollection<MapBookmark> objects (aka. the named Map.Extent values).
/// Collections.ObjectModel.ObservableCollection<ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark> theBookmarks = null;
/// theBookmarks = MyBookmarks.Bookmarks;
/// //theBookmarks = myDataGrid.ItemsSource; // This would work too!
///
/// // Only perform this operation if there at least one named Map.Extent (aka. a bookmark) value.
/// if (theBookmarks.Count > 0)
/// {
/// // Screen out the second firing of this Event.
/// if (myDataGrid.SelectedIndex != -1)
/// {
/// // Set the Member variable to the currently selected cell in the DataGrid sub-component of the BookMark
/// // Control. NOTE: the DataGrid.SelectionMode was set to 'Single' in XAML so that only one bookmark could
/// // be selected at a time for the ClearSelectedBookmark Button to work appropriately.
/// _SelectedIndex = myDataGrid.SelectedIndex;
/// }
/// }
/// }
///
/// private void ClearSelectedBookmark_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function deletes a named Map.Extent (aka. a bookmark) from the DataGrid portion of the
/// // Bookmark Control via its index location. The _SelectedIndex object is a global (aka. Member)
/// // variable and hold the current value of the DataGrid.SelectedItem.
///
/// // Only process _SelectedIndex values not equal to -1.
/// if (_SelectedIndex != -1)
/// {
/// // Delete the specific named Map.Extent (aka. a bookmark) at the specified _SelectedIndex value.
/// MyBookmarks.DeleteBookmarkAt(_SelectedIndex);
/// }
/// }
///
/// private void AddBookmarkNEW_Click(object sender, System.Windows.RoutedEventArgs e)
/// {
/// // This function obtains the sub-component TextBox that of the Bookmark Control where the user
/// // enters a name for the Map.Extent from the XAML hierarchy defined in the ControlTemplate. In
/// // the case of the XAML code you need to go up two levels (i.e. Parent) in order to use the
/// // .FindName() function to obtain the desired TextBox by its name. Then add a named Map.Extent
/// // (aka. a bookmark) to the DataGrid sub-components of the Bookmark Control. Finally, clear out
/// // the text of the TextBox after the newly added Bookmark was added.
///
/// // Traverse through the ControlTemplate hierarchy of controls to find the desired TextBox.
/// Button myButton = (Button)sender;
/// Grid myGrid1 = (Grid)myButton.Parent;
/// Grid mygrid2 = (Grid)myGrid1.Parent;
/// TextBox myTextBox = (TextBox)mygrid2.FindName("AddBookmarkName");
///
/// // Add a bookmark for the current Map.Extent using the name in the TextBox provided by the user.
/// MyBookmarks.AddBookmark(myTextBox.Text, MyMap.Extent);
///
/// // Clear out the text in the TextBox for the next round.
/// myTextBox.Text = "";
/// }
///
///
/// ' This is a Member (aka. Global) variable that will contain the currently selected index value
/// ' for the DataGrid sub-componet in the Bookmark Control.
/// Public _SelectedIndex As Integer = -1
///
/// Private Sub BookmarkList_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
///
/// ' This function obtains the index location of the last cell a user clicked in the DataGrid
/// ' sub-component in the Bookmark Control. It stores that value in the Global variable _SelectedIndex.
///
/// ' Note: There is a bug in the Bookmark.SelectionChanged Event where it always fires twice when a
/// ' DataGrid cell is selected. The first time the Bookmark.SelectionChanged Event fires the correct
/// ' DataGrid.SelectedIndex value is obtained but then the Event fires a second time and always
/// ' set the DataGrid.SelectedIndex value to -1. So this code is a workaround.
///
/// ' Get the DataGrid sub-component of the Bookmark Control.
/// Dim myDataGrid As DataGrid = sender
///
/// ' Get the ObservableCollection(Of MapBookmark) objects (aka. the named Map.Extent values).
/// Dim theBookmarks As Collections.ObjectModel.ObservableCollection(Of ESRI.ArcGIS.Client.Toolkit.Bookmark.MapBookmark)
/// theBookmarks = MyBookmarks.Bookmarks
/// 'theBookmarks = myDataGrid.ItemsSource 'This would work too!
///
/// ' Only perform this operation if there at least one named Map.Extent (aka. a bookmark) value.
/// If theBookmarks.Count > 0 Then
///
/// ' Screen out the second firing of this Event.
/// If myDataGrid.SelectedIndex <> -1 Then
///
/// ' Set the Member variable to the currently selected cell in the DataGrid sub-component of the BookMark
/// ' Control. NOTE: the DataGrid.SelectionMode was set to 'Single' in XAML so that only one bookmark could
/// ' be selected at a time for the ClearSelectedBookmark Button to work appropriately.
/// _SelectedIndex = myDataGrid.SelectedIndex
///
/// End If
///
/// End If
///
/// End Sub
///
/// Private Sub ClearSelectedBookmark_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function deletes a named Map.Extent (aka. a bookmark) from the DataGrid portion of the
/// ' Bookmark Control via its index location. The _SelectedIndex object is a global (aka. Member)
/// ' variable and hold the current value of the DataGrid.SelectedItem.
///
/// ' Only process _SelectedIndex values not equal to -1.
/// If _SelectedIndex <> -1 Then
///
/// ' Delete the specific named Map.Extent (aka. a bookmark) at the specified _SelectedIndex value.
/// MyBookmarks.DeleteBookmarkAt(_SelectedIndex)
///
/// End If
///
/// End Sub
///
/// Private Sub AddBookmarkNEW_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
///
/// ' This function obtains the sub-component TextBox that of the Bookmark Control where the user
/// ' enters a name for the Map.Extent from the XAML hierarchy defined in the ControlTemplate. In
/// ' the case of the XAML code you need to go up two levels (i.e. Parent) in order to use the
/// ' .FindName() function to obtain the desired TextBox by its name. Then add a named Map.Extent
/// ' (aka. a bookmark) to the DataGrid sub-components of the Bookmark Control. Finally, clear out
/// ' the text of the TextBox after the newly added Bookmark was added.
///
/// ' Traverse through the ControlTemplate hierarchy of controls to find the desired TextBox.
/// Dim myButton As Button = sender
/// Dim myGrid1 As Grid = myButton.Parent
/// Dim mygrid2 As Grid = myGrid1.Parent
/// Dim myTextBox As TextBox = mygrid2.FindName("AddBookmarkName")
///
/// ' Add a bookmark for the current Map.Extent using the name in the TextBox provided by the user.
/// MyBookmarks.AddBookmark(myTextBox.Text, MyMap.Extent)
///
/// ' Clear out the text in the TextBox for the next round.
/// myTextBox.Text = ""
///
/// End Sub
///
///
/// The index value of the bookmark to remove from the ObservableCollection.
public void DeleteBookmarkAt(int index)
{
Bookmarks.RemoveAt(index);
#if SILVERLIGHT
SaveBookmarks();
#endif
}
///
/// Clears the bookmarks.
///
public void ClearBookmarks()
{
Bookmarks.Clear();
#if SILVERLIGHT
SaveBookmarks();
#endif
}
#if SILVERLIGHT
///
/// Gets or sets a value indicating whether to store the booksmarks in the isolated storage.
///
/// true if bookmarks will be stored between sessions.
public bool UseIsolatedStorage { get; set; }
#endif
///
/// Gets or sets the title.
///
/// The title.
public string Title
{
get
{
return GetValue(TitleProperty) as string;
}
set
{
SetValue(TitleProperty, value);
}
}
///
/// Identifies the dependency property.
///
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(Bookmark), null);
}
}