Skip to content

PointStyle Guide

Namespace: ThinkGeo.Core
Applies to: All ThinkGeo products (WPF, WinForms, Blazor, MAUI, GIS Server, etc.)


Overview

PointStyle controls how point features — hotels, capitals, crime incidents, sensor readings, or any other single-coordinate geometry — are drawn on the map. It supports three distinct rendering modes that share the same class:

  • Symbol mode — a built-in geometric shape (PointSymbolType enum: circles, squares, diamonds, triangles, etc.) filled and outlined with GeoBrush/GeoPen values.
  • Image mode — an external raster image (GeoImage) displayed at the point location, scaled with ImageScale or SymbolSize.
  • Font/character mode — a single character rendered in a GeoFont, optionally masked with an AreaStyle background.

All three modes use the same property set (SymbolSize, RotationAngle, Mask, MaskType, IsActive) and are attached to a layer the same way.


Constructors

Symbol mode — PointSymbolType + size + fill + outline

The most common constructor. Takes a shape type, pixel size, fill brush, and optional outline pen.

// Fill + outline
var pointStyle = new PointStyle(PointSymbolType.Circle, 12, GeoBrushes.Blue, new GeoPen(GeoBrushes.White, 2));

// Fill only (no outline overload — omit the GeoPen argument)
var pointStyle = new PointStyle(PointSymbolType.Circle, 4, GeoBrushes.DarkRed, new GeoPen(GeoBrushes.White, 2));

Sources: wpfHowDoI:Samples/VectorDataStyling/RenderPoints.xaml.cs, winformHowDoI:Samples/VectorDataStyling/RenderBasedOnScales.cs, mauiHowDoI:Samples/VectorDataStyling/CreatePointStyle.xaml.cs.

Scale-dependent sizes — pass different sizes per zoom range:

// Small dot at zoom levels 12-13
hotelsLayer.ZoomLevelSet.ZoomLevel12.DefaultPointStyle =
    new PointStyle(PointSymbolType.Circle, 4, GeoBrushes.DarkRed, new GeoPen(GeoBrushes.White, 2));
hotelsLayer.ZoomLevelSet.ZoomLevel12.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level13;

// Medium dot at zoom levels 14-15
hotelsLayer.ZoomLevelSet.ZoomLevel14.DefaultPointStyle =
    new PointStyle(PointSymbolType.Circle, 8, GeoBrushes.DarkRed, new GeoPen(GeoBrushes.White, 2));
hotelsLayer.ZoomLevelSet.ZoomLevel14.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level15;

// Large dot at zoom levels 16-20
hotelsLayer.ZoomLevelSet.ZoomLevel16.DefaultPointStyle =
    new PointStyle(PointSymbolType.Circle, 12, GeoBrushes.DarkRed, new GeoPen(GeoBrushes.White, 2));
hotelsLayer.ZoomLevelSet.ZoomLevel16.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Source: winformHowDoI:Samples/VectorDataStyling/RenderBasedOnScales.cs.

Symbol mode — GeoSolidBrush with GeoColor.FromArgb (semi-transparent or fully transparent sentinel)

// Transparent sentinel for ClassBreakStyle
new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColors.Transparent))

// Semi-transparent colored fill
new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColor.FromArgb(alpha, 255, 0, 0)))

Source: wpfHowDoI:Samples/MapOfflineData/Vector/GenerateESRIGridFile.xaml.cs.

Image mode — GeoImage

Pass a GeoImage wrapping a file path (WPF/WinForms) or an async stream (MAUI). Use ImageScale (relative multiplier) or SymbolSize (absolute pixel size) to control the rendered dimensions.

// WPF / WinForms — file path
var pointStyle = new PointStyle(new GeoImage(@"./Resources/hotel_icon.png"))
{
    ImageScale = .25
};

// WinForms — larger background circle + scaled image icon layered in a FilterStyle
new PointStyle(PointSymbolType.Circle, 28, GeoBrushes.White, GeoPens.Red),
new PointStyle(new GeoImage(@"../../../Resources/drugs_icon.png")) { ImageScale = .60 }

// MAUI — async package file stream
_imageStyle = new PointStyle(new GeoImage(await FileSystem.OpenAppPackageFileAsync("hotel_icon.png")))
{
    SymbolSize = 40,
    IsActive = false
};

Sources: wpfHowDoI:Samples/VectorDataStyling/RenderPoints.xaml.cs, winformHowDoI:Samples/VectorDataStyling/RenderBasedOnFilters.cs, mauiHowDoI:Samples/VectorDataStyling/CreatePointStyle.xaml.cs.

Font/character mode — GeoFont + character string + fill brush

Renders a single character from a font at each feature location. Typically combined with a Mask background to make the character legible.

var symbolPointStyle = new PointStyle(new GeoFont("Verdana", 16, DrawingFontStyles.Bold), "@", GeoBrushes.Black)
{
    Mask = new AreaStyle(GeoBrushes.White),
    MaskType = MaskType.Circle
};

Sources: wpfHowDoI:Samples/VectorDataStyling/RenderPoints.xaml.cs, winformHowDoI:Samples/VectorDataStyling/RenderPoints.cs, mauiHowDoI:Samples/VectorDataStyling/CreatePointStyle.xaml.cs.


Static Factory Method

CreateSimpleCircleStyle

Shorthand for a solid filled circle with an outline. Commonly used when constructing styles as property values inside other style wrappers.

PointStyle.CreateSimpleCircleStyle(GeoColors.Yellow, 12, GeoColors.Black)
PointStyle.CreateSimpleCircleStyle(GeoColors.Gray, 12, GeoColors.Black)

Sources: winformHowDoI:Samples/VectorDataStyling/CustomStyles.cs, wpfHowDoI:Samples/VectorDataStyling/CustomStyles.xaml.cs, mauiHowDoI:Samples/VectorDataStyling/ExtendingStyles.xaml.cs.


Properties

These properties apply across all three constructor modes and are read back the same way. Source: blazorHowDoI:Shared/LayerBuilder.cs.

Property Type Description
SymbolType PointSymbolType The geometric shape used in symbol mode (Circle, Square, Diamond, Triangle, etc.).
SymbolSize float Size in pixels. For image mode this sets the rendered width/height directly; for symbol mode it controls the radius/extent of the shape.
RotationAngle float Rotation in degrees, applied clockwise around the feature's point.
FillBrush GeoBrush The fill color for symbol mode. Cast to GeoSolidBrush to read back the GeoColor.
OutlinePen GeoPen The outline pen for symbol mode.
ImageScale float Multiplier applied to the source image's natural size in image mode. .25 = quarter size.
Mask AreaStyle Background shape drawn behind the symbol/character.
MaskType MaskType Shape of the mask — MaskType.Circle, MaskType.Rectangle, etc.
IsActive bool When false the style is skipped during rendering without being removed. Useful for toggling between styles added to the same CustomStyles collection.

Reading properties back (Blazor inspector pattern):

PointStyle targetPointStyle = featureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle;

PointSymbolType type = targetPointStyle.SymbolType;
float size            = targetPointStyle.SymbolSize;
float angle           = targetPointStyle.RotationAngle;

GeoPen pen            = targetPointStyle.OutlinePen;
GeoColor penColor     = pen.Color;
float penWidth        = pen.Width;

GeoColor fillColor    = ((GeoSolidBrush)targetPointStyle.FillBrush).Color;

Source: blazorHowDoI:Shared/LayerBuilder.cs.


Attaching a Style to a Layer

DefaultPointStyle — single-style case

hotelsLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle =
    new PointStyle(PointSymbolType.Circle, 12, GeoBrushes.Blue, new GeoPen(GeoBrushes.White, 2));
hotelsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

CustomStyles — multiple styles or mixing with TextStyle

Use CustomStyles when you need more than one PointStyle stacked on the same zoom level (e.g., a background circle + an icon image), or when combining with a TextStyle.

// Stack a background circle + a scaled image icon
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Clear();
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(
    new PointStyle(PointSymbolType.Circle, 28, GeoBrushes.White, GeoPens.Red));
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(
    new PointStyle(new GeoImage(@"./Resources/hotel_icon.png")) { ImageScale = .60 });
hotelsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Source: winformHowDoI:Samples/VectorDataStyling/RenderBasedOnFilters.cs.

Combine with a TextStyle:

var pointStyle = new PointStyle(PointSymbolType.Circle, 4, GeoBrushes.Brown,
    new GeoPen(GeoBrushes.DarkRed, 2));
var textStyle = new TextStyle("NAME", new GeoFont("Segoe UI", 12, DrawingFontStyles.Bold), GeoBrushes.DarkRed)
{
    TextPlacement = TextPlacement.Center,
    HaloPen = new GeoPen(GeoBrushes.White, 2),
    DrawingLevel = DrawingLevel.LabelLevel,
    AllowLineCarriage = true,
    YOffsetInPixel = -10
};

hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(pointStyle);
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(textStyle);
hotelsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Source: mauiHowDoI:Samples/VectorDataStyling/CreateTextStyle.xaml.cs.

Toggling between styles with IsActive

Add all styles to CustomStyles at setup, then flip IsActive at runtime instead of clearing and re-adding:

// Setup — all three added, only predefined is active initially
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(_predefinedStyle);   // IsActive = true (default)
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(_imageStyle);        // IsActive = false
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(_fontStyle);         // IsActive = false
hotelsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

// Switch to image style at runtime
_predefinedStyle.IsActive = false;
_imageStyle.IsActive = true;
_fontStyle.IsActive = false;
await _layerOverlay.RefreshAsync();

Source: mauiHowDoI:Samples/VectorDataStyling/CreatePointStyle.xaml.cs.


Using PointStyle inside ClassBreakStyle

ClassBreakStyle assigns a different PointStyle to features based on a numeric column value. The pattern is identical to AreaStyle in a ClassBreakStyle: use a transparent sentinel for the lowest break and colored fills for the remaining thresholds.

var classBreakStyle = new ClassBreakStyle("PH");
const byte alpha = 180;
const int symbolSize = 10;

classBreakStyle.ClassBreaks.Add(
    new ClassBreak(double.MinValue,
        new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColors.Transparent))));
classBreakStyle.ClassBreaks.Add(
    new ClassBreak(6.2,
        new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColor.FromArgb(alpha, 255, 0, 0)))));
classBreakStyle.ClassBreaks.Add(
    new ClassBreak(6.83,
        new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColor.FromArgb(alpha, 255, 128, 0)))));
classBreakStyle.ClassBreaks.Add(
    new ClassBreak(7.0,
        new PointStyle(PointSymbolType.Circle, symbolSize, new GeoSolidBrush(GeoColor.FromArgb(alpha, 245, 210, 10)))));
// ... additional breaks ...

samplesLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(classBreakStyle);
samplesLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Source: wpfHowDoI:Samples/MapOfflineData/Vector/GenerateESRIGridFile.xaml.cs, winformHowDoI:Samples/MapOfflineData/Vector/GenerateESRIGridFile.cs.


Using PointStyle inside FilterStyle

FilterStyle applies a group of styles only to features that match a column-value condition. Stacking a symbol background with an image icon inside a FilterStyle is the standard pattern for category-icon maps.

var drugFilterStyle = new FilterStyle()
{
    Conditions = { new FilterCondition("OffenseGro", "Drugs") },
    Styles = {
        new PointStyle(PointSymbolType.Circle, 28, GeoBrushes.White, GeoPens.Red),
        new PointStyle(new GeoImage(@"./Resources/drugs_icon.png")) { ImageScale = .60 }
    }
};

var weaponFilterStyle = new FilterStyle()
{
    Conditions = { new FilterCondition("OffenseGro", "Weapons") },
    Styles = {
        new PointStyle(PointSymbolType.Circle, 28, GeoBrushes.White, GeoPens.Red),
        new PointStyle(new GeoImage(@"./Resources/weapon_icon.png")) { ImageScale = .25 }
    }
};

Source: wpfHowDoI:Samples/VectorDataStyling/RenderBasedOnFilters.xaml.cs, winformHowDoI:Samples/VectorDataStyling/RenderBasedOnFilters.cs, mauiHowDoI:Samples/VectorDataStyling/CreateFilterStyle.xaml.cs.


Using PointStyle as a property value

PointStyle instances can appear as property values on other objects, not just directly on zoom levels. The CreateSimpleCircleStyle factory method is particularly convenient in these contexts.

// As properties of a custom style wrapper
var timeBasedPointStyle = new TimeBasedPointStyle
{
    TimeZoneColumnName = "TimeZone",
    DaytimePointStyle  = PointStyle.CreateSimpleCircleStyle(GeoColors.Yellow, 12, GeoColors.Black),
    NighttimePointStyle = PointStyle.CreateSimpleCircleStyle(GeoColors.Gray, 12, GeoColors.Black)
};

// As the inner style of a SizedPointStyle (scales point size by a column value)
var sizedPointStyle = new SizedPointStyle(
    PointStyle.CreateSimpleCircleStyle(GeoColors.Blue, 1),
    "population",
    500000);

Sources: winformHowDoI:Samples/VectorDataStyling/CustomStyles.cs, wpfHowDoI:Samples/VectorDataStyling/CustomStyles.xaml.cs, mauiHowDoI:Samples/VectorDataStyling/ExtendingStyles.xaml.cs.


Common Patterns and Pitfalls

CustomStyles.Clear() before re-assigning. When switching the symbol type at runtime (e.g., from a circle to an icon in response to a UI event), always call CustomStyles.Clear() before adding the new style — otherwise the old style remains and both render on top of each other. The IsActive approach described above avoids this issue entirely.

hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Clear();
hotelsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(newPointStyle);
await layerOverlay.RefreshAsync();

ImageScale vs SymbolSize for image mode. ImageScale is a multiplier against the image's natural pixel dimensions (.25 = 25% of original size). SymbolSize is an absolute pixel target. Use ImageScale when your icon has a predictable natural size and you want it to scale proportionally; use SymbolSize when you need a specific rendered size regardless of source dimensions.

GeoPens named constants. GeoPens.Red and GeoPens.DimGray are pre-built GeoPen instances (equivalent to new GeoPen(GeoBrushes.Red, 1)). They are valid anywhere a GeoPen is accepted and are interchangeable with new GeoPen(GeoColors.Red, 1).

Refreshing after style changes. Changing a style at runtime has no visible effect until the overlay is refreshed:

await layerOverlay.RefreshAsync();  // or MapView.RefreshAsync() if you need all overlays

Source References

Sample Namespace PointStyle usage
VectorDataStyling/RenderPoints WPF, WinForms All three modes — symbol, image, font/character
VectorDataStyling/CreatePointStyle MAUI All three modes + IsActive toggling
VectorDataStyling/RenderBasedOnScales WPF, WinForms, MAUI Symbol mode; scale-dependent sizes via DefaultPointStyle
VectorDataStyling/CreateTextStyle MAUI Symbol mode + TextStyle in CustomStyles
VectorDataStyling/RenderBasedOnFilters WPF, WinForms Image + symbol stacking inside FilterStyle
VectorDataStyling/CreateFilterStyle MAUI Image + symbol stacking inside FilterStyle
VectorDataStyling/CustomStyles WPF, WinForms CreateSimpleCircleStyle as a property value; SizedPointStyle
VectorDataStyling/ExtendingStyles MAUI CreateSimpleCircleStyle as a property value
Shared/LayerBuilder.cs Blazor Reading SymbolType, SymbolSize, RotationAngle, OutlinePen, FillBrush
MapOfflineData/GenerateESRIGridFile WPF, WinForms ClassBreakStyle + PointStyle color ramp with transparent sentinel