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 (
PointSymbolTypeenum: circles, squares, diamonds, triangles, etc.) filled and outlined withGeoBrush/GeoPenvalues. - Image mode — an external raster image (
GeoImage) displayed at the point location, scaled withImageScaleorSymbolSize. - Font/character mode — a single character rendered in a
GeoFont, optionally masked with anAreaStylebackground.
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 |