public static DataTemplate BuildMapTipDataTemplate(PopupItem popupItem, out bool hasContent, LayerInformation layerInfo = null)
		{
			hasContent = false;
            if (popupItem == null || popupItem.Graphic == null || popupItem.Graphic.Attributes == null || popupItem.Layer == null)
                return null;

            Layer layer = popupItem.Layer;
			string popupDataTemplatesXaml = null;
            #region Get from developer override/webmap override
            //First get from developer override
            IDictionary<int, string> templates = ESRI.ArcGIS.Client.Extensibility.LayerProperties.GetPopupDataTemplates(layer);
            //then if defined in web map
            if (templates == null && ESRI.ArcGIS.Mapping.Core.LayerExtensions.GetUsePopupFromWebMap(layer))
                templates = ESRI.ArcGIS.Mapping.Core.LayerExtensions.GetWebMapPopupDataTemplates(layer);
            if (templates != null)
            {
                if (layer is GraphicsLayer)
                    popupDataTemplatesXaml = (templates.ContainsKey(-1)) ? templates[-1] : null;
                else
                    popupDataTemplatesXaml = (templates.ContainsKey(layerInfo.ID)) ? templates[layerInfo.ID] : null;
            }
            #endregion

			DataTemplate dt = null;
			StringBuilder sb = new StringBuilder();
            if (!string.IsNullOrEmpty(popupDataTemplatesXaml))
            {
                // Use popup data template xaml.
                hasContent = true;
                sb.Append(popupDataTemplatesXaml);
            }
            else
            {
                sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" ");
                sb.Append("xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" ");
                sb.Append("xmlns:mapping=\"http://schemas.esri.com/arcgis/mapping/2009\" ");
                sb.Append("xmlns:local=\"clr-namespace:ESRI.ArcGIS.Mapping.Controls;assembly=ESRI.ArcGIS.Mapping.Controls\" >");
                sb.Append("<Grid HorizontalAlignment=\"Stretch\"><Grid.Resources>");
                sb.Append("<mapping:LabelAttributeConverter x:Key=\"LabelAttributeConverter\" />");
                sb.Append("<mapping:UrlLocationAttributeConverter x:Key=\"UrlLocationAttributeConverter\" />");
                sb.Append("<mapping:UrlDescriptionAttributeConverter x:Key=\"UrlDescriptionAttributeConverter\" />");
                sb.Append("</Grid.Resources>");

                if (popupItem.FieldInfos != null)
                {
                    // Grid with three columns:
                    sb.Append("<Grid.ColumnDefinitions>");
                    sb.Append("<ColumnDefinition Width=\"2*\"/>");
                    sb.Append("<ColumnDefinition Width=\"Auto\"/>");
                    sb.Append("<ColumnDefinition Width=\"3*\" />");
                    sb.Append("</Grid.ColumnDefinitions>");

                    string gridRowDefinitions = string.Empty;
                    StringBuilder content = new StringBuilder();
                    int numRows = 0;
                    foreach (FieldSettings field in popupItem.FieldInfos)
                    {
                        // If field is not to be displayed, skip this field
                        if (!field.VisibleOnMapTip)
                            continue;

                        hasContent = true;
                        gridRowDefinitions += "<RowDefinition Height=\"Auto\" />";
                        numRows++;

                        // Apply alternating row background to every other row
                        if (numRows % 2 == 0)
                        {
                            content.AppendFormat(@"<Rectangle Fill=""{{StaticResource BackgroundTextColorBrush}}""
                                                HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""
                                                Grid.ColumnSpan=""3"" Grid.Row=""{0}"" Opacity=""0.15"" />", numRows - 1);
                        }

                        if (!string.IsNullOrEmpty(field.DisplayName))
                        {
                            // This is where we will eventually add code that uses an expression to plug in the actual
                            // value for a field name when curly braces are detected (or something).
                            content.AppendFormat(@"<Grid Grid.Row=""{0}""><TextBlock Grid.Column=""0"" Text=""{1}"" 
                                                Margin=""5,2"" Opacity="".6"" VerticalAlignment=""Center"" 
                                                TextWrapping=""Wrap"" /></Grid>",
                                numRows - 1, PopupInfo.SafeXML(field.DisplayName));
                        }

                        // Process this field regardless of value. We need to create a control that has binding so that as
                        // the value changes during editing the control will adapt and display null and not-null values
                        // properly.
                        object o = GetFieldValue(popupItem, field.Name);
                        StringBuilder element = GetFieldValueElement(field, o, numRows - 1);
                        if (element != null)
                        {
                            content.Append(element);
                        }

                        // Column separator
                        content.AppendFormat(@"<Rectangle Fill=""{{StaticResource BackgroundTextColorBrush}}""
                                                HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""
                                                Grid.Column=""1"" Grid.Row=""{0}"" Opacity=""0.3"" Width=""1""/>", 
                                                numRows - 1);
                    }

                    #region Add Open Item hyperlink
                    if (layer is CustomGraphicsLayer)
                    {
                        ESRI.ArcGIS.Client.Application.Layout.Converters.LocalizationConverter converter = new Client.Application.Layout.Converters.LocalizationConverter();
                        gridRowDefinitions += "<RowDefinition Height=\"Auto\" />";
                        numRows++;
                        content.AppendFormat("<HyperlinkButton Content=\"{0}\" Grid.ColumnSpan=\"2\" Grid.Row=\"{1}\" CommandParameter=\"{{Binding}}\"><HyperlinkButton.Command><local:OpenItemCommand/></HyperlinkButton.Command></HyperlinkButton>",
                            converter.Get("OpenItem"), numRows - 1);
                    }
                    #endregion

                    if (!string.IsNullOrEmpty(gridRowDefinitions))
                        sb.AppendFormat("<Grid.RowDefinitions>{0}</Grid.RowDefinitions>", gridRowDefinitions);
                    sb.Append(content.ToString());
                }
                sb.Append("</Grid></DataTemplate>");
            }
			try
			{
				dt = (DataTemplate)System.Windows.Markup.XamlReader.Load(sb.ToString());
            }
			catch { /* No content */ }

			return dt;
		}
        public static DataTemplate BuildMapTipDataTemplate(PopupItem popupItem, out bool hasContent, LayerInformation layerInfo = null)
        {
            hasContent = false;
            if (popupItem == null || popupItem.Graphic == null || popupItem.Graphic.Attributes == null || popupItem.Layer == null)
            {
                return(null);
            }

            Layer  layer = popupItem.Layer;
            string popupDataTemplatesXaml = null;

            #region Get from developer override/webmap override
            //First get from developer override
            IDictionary <int, string> templates = ESRI.ArcGIS.Client.Extensibility.LayerProperties.GetPopupDataTemplates(layer);
            //then if defined in web map
            if (templates == null && ESRI.ArcGIS.Mapping.Core.LayerExtensions.GetUsePopupFromWebMap(layer))
            {
                templates = ESRI.ArcGIS.Mapping.Core.LayerExtensions.GetWebMapPopupDataTemplates(layer);
            }
            if (templates != null)
            {
                if (layer is GraphicsLayer)
                {
                    popupDataTemplatesXaml = (templates.ContainsKey(-1)) ? templates[-1] : null;
                }
                else
                {
                    popupDataTemplatesXaml = (templates.ContainsKey(layerInfo.ID)) ? templates[layerInfo.ID] : null;
                }
            }
            #endregion

            DataTemplate  dt = null;
            StringBuilder sb = new StringBuilder();
            if (!string.IsNullOrEmpty(popupDataTemplatesXaml))
            {
                // Use popup data template xaml.
                hasContent = true;
                sb.Append(popupDataTemplatesXaml);
            }
            else
            {
                sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" ");
                sb.Append("xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" ");
                sb.Append("xmlns:mapping=\"http://schemas.esri.com/arcgis/mapping/2009\" ");
                sb.Append("xmlns:local=\"clr-namespace:ESRI.ArcGIS.Mapping.Controls;assembly=ESRI.ArcGIS.Mapping.Controls\" >");
                sb.Append("<Grid HorizontalAlignment=\"Stretch\"><Grid.Resources>");
                sb.Append("<mapping:LabelAttributeConverter x:Key=\"LabelAttributeConverter\" />");
                sb.Append("<mapping:UrlLocationAttributeConverter x:Key=\"UrlLocationAttributeConverter\" />");
                sb.Append("<mapping:UrlDescriptionAttributeConverter x:Key=\"UrlDescriptionAttributeConverter\" />");
                sb.Append("</Grid.Resources>");

                if (popupItem.FieldInfos != null)
                {
                    // Grid with three columns:
                    sb.Append("<Grid.ColumnDefinitions>");
                    sb.Append("<ColumnDefinition Width=\"2*\"/>");
                    sb.Append("<ColumnDefinition Width=\"Auto\"/>");
                    sb.Append("<ColumnDefinition Width=\"3*\" />");
                    sb.Append("</Grid.ColumnDefinitions>");

                    string        gridRowDefinitions = string.Empty;
                    StringBuilder content            = new StringBuilder();
                    int           numRows            = 0;
                    foreach (FieldSettings field in popupItem.FieldInfos)
                    {
                        // If field is not to be displayed, skip this field
                        if (!field.VisibleOnMapTip)
                        {
                            continue;
                        }

                        hasContent          = true;
                        gridRowDefinitions += "<RowDefinition Height=\"Auto\" />";
                        numRows++;

                        // Apply alternating row background to every other row
                        if (numRows % 2 == 0)
                        {
                            content.AppendFormat(@"<Rectangle Fill=""{{StaticResource BackgroundTextColorBrush}}""
                                                HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""
                                                Grid.ColumnSpan=""3"" Grid.Row=""{0}"" Opacity=""0.15"" />", numRows - 1);
                        }

                        if (!string.IsNullOrEmpty(field.DisplayName))
                        {
                            // This is where we will eventually add code that uses an expression to plug in the actual
                            // value for a field name when curly braces are detected (or something).
                            content.AppendFormat(@"<Grid Grid.Row=""{0}""><TextBlock Grid.Column=""0"" Text=""{1}"" 
                                                Margin=""5,2"" Opacity="".6"" VerticalAlignment=""Center"" 
                                                TextWrapping=""Wrap"" /></Grid>",
                                                 numRows - 1, PopupInfo.SafeXML(field.DisplayName));
                        }

                        // Process this field regardless of value. We need to create a control that has binding so that as
                        // the value changes during editing the control will adapt and display null and not-null values
                        // properly.
                        object        o       = GetFieldValue(popupItem, field.Name);
                        StringBuilder element = GetFieldValueElement(field, o, numRows - 1);
                        if (element != null)
                        {
                            content.Append(element);
                        }

                        // Column separator
                        content.AppendFormat(@"<Rectangle Fill=""{{StaticResource BackgroundTextColorBrush}}""
                                                HorizontalAlignment=""Stretch"" VerticalAlignment=""Stretch""
                                                Grid.Column=""1"" Grid.Row=""{0}"" Opacity=""0.3"" Width=""1""/>",
                                             numRows - 1);
                    }

                    #region Add Open Item hyperlink
                    if (layer is CustomGraphicsLayer)
                    {
                        ESRI.ArcGIS.Client.Application.Layout.Converters.LocalizationConverter converter = new Client.Application.Layout.Converters.LocalizationConverter();
                        gridRowDefinitions += "<RowDefinition Height=\"Auto\" />";
                        numRows++;
                        content.AppendFormat("<HyperlinkButton Content=\"{0}\" Grid.ColumnSpan=\"2\" Grid.Row=\"{1}\" CommandParameter=\"{{Binding}}\"><HyperlinkButton.Command><local:OpenItemCommand/></HyperlinkButton.Command></HyperlinkButton>",
                                             converter.Get("OpenItem"), numRows - 1);
                    }
                    #endregion

                    if (!string.IsNullOrEmpty(gridRowDefinitions))
                    {
                        sb.AppendFormat("<Grid.RowDefinitions>{0}</Grid.RowDefinitions>", gridRowDefinitions);
                    }
                    sb.Append(content.ToString());
                }
                sb.Append("</Grid></DataTemplate>");
            }
            try
            {
                dt = (DataTemplate)System.Windows.Markup.XamlReader.Load(sb.ToString());
            }
            catch { /* No content */ }

            return(dt);
        }