Select to view content in your preferred language

Stroke on a line symbol

1100
4
06-02-2011 03:52 PM
DonFreeman
Emerging Contributor
Is there a line symbol type that allows you to put a border (stroke) around the line to provide enhanced definition? Is there a sample somewhere?
Thanks
0 Kudos
4 Replies
DominiqueBroux
Esri Frequent Contributor
A line symbol uses the path stroke property to define the main color, so it's not possible to get a border to the line with only one path element.

One approach might be to define a symbol with many paths having various colors and thicknesses.
Something like:
<esri:SimpleLineSymbol x:Key="myExtendedLineSymbol" Color="Blue" Width="10" >
    <esri:SimpleLineSymbol.ControlTemplate>
        <ControlTemplate>
            <Grid>
                <Grid.Resources>
                    <local:CloneGeometryConverter x:Key="cloneConverter" />
                    <esri:MultiplicationConverter x:Key="multiplicationConverter" />
                </Grid.Resources>
                <Path x:Name="Element" Stroke="{Binding Symbol.Color}" StrokeThickness="{Binding Symbol.Width}"
                        StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
                <Path Stroke="White" StrokeThickness="{Binding Symbol.Width, Converter={StaticResource multiplicationConverter}, ConverterParameter=0.6}"
                        StrokeEndLineCap="Round" StrokeStartLineCap="Round"
                        Data="{Binding Path=Data, ElementName=Element, Converter={StaticResource cloneConverter}}"
                        />
                <Path Stroke="Red" StrokeThickness="{Binding Symbol.Width, Converter={StaticResource multiplicationConverter}, ConverterParameter=0.2}"
                        StrokeEndLineCap="Round" StrokeStartLineCap="Round"
                        Data="{Binding Path=Data, ElementName=Element, Converter={StaticResource cloneConverter}}"
                        />
            </Grid>
        </ControlTemplate>
    </esri:SimpleLineSymbol.ControlTemplate>
</esri:SimpleLineSymbol>


which gives the attached screenshot as result.

Important note : I am not sure this approach is fully supported by ESRI because the root element of the line symbol is not a path. So despite it looks working well at first glance, consider this as an unsupported approach without any ESRI guarantee.

You will also need code to clone a geometry (without cloning it we get a crash).
Here is the code I found on the Web:
public class CloneGeometryConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (targetType == typeof(System.Windows.Media.Geometry) && value is System.Windows.Media.Geometry)
            return Clone(value as System.Windows.Media.Geometry);
        return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
 
    // Code coming from http://kiwigis.blogspot.com/2010/06/cloning-path-geometry-in-silverlight.html
    private static object Clone(Object obj)
    {
        // Get all properties and clone them.
        PropertyInfo[] properties = obj.GetType().GetProperties();
        object cloneObj = obj.GetType().GetConstructors()[0].Invoke(null);
        foreach (PropertyInfo property in properties)
        {
            object value = property.GetValue(obj, null);
            if (value != null)
            {
                if (IsPresentationFrameworkCollection(value.GetType()))
                {
                    object collection = property.GetValue(obj, null);
                    int count = (int)collection.GetType().GetProperty("Count").GetValue(collection, null);
                    for (int i = 0; i < count; i++)
                    {
                        // Get each child of the collection.
                        object child = collection.GetType().GetProperty("Item").GetValue(collection, new Object[] { i });
                        object cloneChild = Clone(child);
                        object cloneCollection = property.GetValue(cloneObj, null);
                        collection.GetType().InvokeMember("Add", BindingFlags.InvokeMethod, null, cloneCollection, new object[] { cloneChild });
                    }
                }
                // If the property is a UIElement, we also need to clone it.
                else if (value is UIElement)
                {
                    object obj2 = property.PropertyType.GetConstructors()[0].Invoke(null);
                    Clone(obj2);
                    property.SetValue(cloneObj, obj2, null);
                }
                // For a normal property, its value doesn't need to be                // cloned. So just copy its value to the new object.
                else if (property.CanWrite)
                {
                    property.SetValue(cloneObj, value, null);
                }
            }
        }
        return cloneObj;
    }
    private static bool IsPresentationFrameworkCollection(Type type)
    {
        if (type == typeof(object))
        {
            return false;
        }
        if (type.Name.StartsWith("PresentationFrameworkCollection"))
        {
            return true;
        }
        return IsPresentationFrameworkCollection(type.BaseType);
    }
}
0 Kudos
DonFreeman
Emerging Contributor
Thanks Dominique. Where does the c# code go? I placed it at the end of my mappage codebehind but the xaml code doesn't see it there even after a build.
0 Kudos
DominiqueBroux
Esri Frequent Contributor

Where does the c# code go? I placed it at the end of my mappage codebehind but the xaml code doesn't see it there even after a build.

Where you want. Your MapPage is OK.
You have just to look at the namespace of the class and check that your are using the right namespace in XAML i.e.
<local:CloneGeometryConverter local must match the namespace of 'CloneGeometryConverter' in your code.
0 Kudos
DonFreeman
Emerging Contributor
Thanks Dominique. I got it working. My problem was the local reference in the xaml code.
0 Kudos