diff --git a/maui/samples/Gallery/ControlList.xml b/maui/samples/Gallery/ControlList.xml
index 4efbbd20..1b6ce05e 100644
--- a/maui/samples/Gallery/ControlList.xml
+++ b/maui/samples/Gallery/ControlList.xml
@@ -13,6 +13,7 @@
+
@@ -28,5 +29,6 @@
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/Resources/Images/gridsplitter.png b/maui/samples/Gallery/Resources/Images/gridsplitter.png
new file mode 100644
index 00000000..01e0cb8e
Binary files /dev/null and b/maui/samples/Gallery/Resources/Images/gridsplitter.png differ
diff --git a/maui/samples/Gallery/Resources/Images/interactiveviewer.png b/maui/samples/Gallery/Resources/Images/interactiveviewer.png
new file mode 100644
index 00000000..e31ece91
Binary files /dev/null and b/maui/samples/Gallery/Resources/Images/interactiveviewer.png differ
diff --git a/maui/samples/Gallery/Resources/Images/interactiveviewerimage.png b/maui/samples/Gallery/Resources/Images/interactiveviewerimage.png
new file mode 100644
index 00000000..a0485655
Binary files /dev/null and b/maui/samples/Gallery/Resources/Images/interactiveviewerimage.png differ
diff --git a/maui/samples/Gallery/SampleList/CartesianChartSamplesList.xml b/maui/samples/Gallery/SampleList/CartesianChartSamplesList.xml
index 88f89c0a..bd24dfad 100644
--- a/maui/samples/Gallery/SampleList/CartesianChartSamplesList.xml
+++ b/maui/samples/Gallery/SampleList/CartesianChartSamplesList.xml
@@ -1,7 +1,7 @@
-
+
@@ -172,7 +172,7 @@
-
+
@@ -183,7 +183,10 @@
-
+
+
@@ -191,6 +194,8 @@
+
+
@@ -205,6 +210,7 @@
+
diff --git a/maui/samples/Gallery/SampleList/FunnelChartSamplesList.xml b/maui/samples/Gallery/SampleList/FunnelChartSamplesList.xml
index 1e229fbb..38ea4f88 100644
--- a/maui/samples/Gallery/SampleList/FunnelChartSamplesList.xml
+++ b/maui/samples/Gallery/SampleList/FunnelChartSamplesList.xml
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/maui/samples/Gallery/SampleList/GridSplitterSamplesList.xml b/maui/samples/Gallery/SampleList/GridSplitterSamplesList.xml
new file mode 100644
index 00000000..be229579
--- /dev/null
+++ b/maui/samples/Gallery/SampleList/GridSplitterSamplesList.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/SampleList/InteractiveViewerSamplesList.xml b/maui/samples/Gallery/SampleList/InteractiveViewerSamplesList.xml
new file mode 100644
index 00000000..079b057b
--- /dev/null
+++ b/maui/samples/Gallery/SampleList/InteractiveViewerSamplesList.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/SampleList/PyramidChartSamplesList.xml b/maui/samples/Gallery/SampleList/PyramidChartSamplesList.xml
index 94d218ab..4804b1ae 100644
--- a/maui/samples/Gallery/SampleList/PyramidChartSamplesList.xml
+++ b/maui/samples/Gallery/SampleList/PyramidChartSamplesList.xml
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/maui/samples/Gallery/SampleList/SparkChartSamplesList.xml b/maui/samples/Gallery/SampleList/SparkChartSamplesList.xml
index 3e2b9e16..c0ebf0ac 100644
--- a/maui/samples/Gallery/SampleList/SparkChartSamplesList.xml
+++ b/maui/samples/Gallery/SampleList/SparkChartSamplesList.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/maui/samples/Gallery/SampleList/SunburstChartSamplesList.xml b/maui/samples/Gallery/SampleList/SunburstChartSamplesList.xml
index 3cdc0001..cb9fd113 100644
--- a/maui/samples/Gallery/SampleList/SunburstChartSamplesList.xml
+++ b/maui/samples/Gallery/SampleList/SunburstChartSamplesList.xml
@@ -1,13 +1,15 @@
-
+
+
diff --git a/maui/samples/Gallery/Samples/Calendar/GettingStarted/View/GettingStarted.xaml b/maui/samples/Gallery/Samples/Calendar/GettingStarted/View/GettingStarted.xaml
index 58b6560d..771e0845 100644
--- a/maui/samples/Gallery/Samples/Calendar/GettingStarted/View/GettingStarted.xaml
+++ b/maui/samples/Gallery/Samples/Calendar/GettingStarted/View/GettingStarted.xaml
@@ -124,7 +124,8 @@
VerticalTextAlignment="Center"/>
+ VerticalOptions="Center"
+ HorizontalOptions ="Start" />
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Annotation/DraggableLineAnnotation.cs b/maui/samples/Gallery/Samples/CartesianChart/Annotation/DraggableLineAnnotation.cs
new file mode 100644
index 00000000..f7081921
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/Annotation/DraggableLineAnnotation.cs
@@ -0,0 +1,578 @@
+using Syncfusion.Maui.Toolkit.Charts;
+
+namespace Syncfusion.Maui.ControlsGallery.Samples.CartesianChart.Annotation
+{
+ ///
+ /// Helper struct to store plot area bounds in axis values.
+ ///
+ internal struct PlotAreaBounds
+ {
+ public double Left { get; set; }
+ public double Right { get; set; }
+ public double Top { get; set; }
+ public double Bottom { get; set; }
+ }
+
+ ///
+ /// Helper class for draggable annotation utilities.
+ ///
+ internal static class DraggableAnnotationHelper
+ {
+ ///
+ /// Calculates plot area bounds in axis values.
+ ///
+ public static PlotAreaBounds GetPlotAreaBounds(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart, ChartAxis xAxis, RangeAxisBase yAxis)
+ {
+ return new PlotAreaBounds
+ {
+ Left = chart.PointToValue(xAxis, (float)chart.SeriesBounds.Left, (float)chart.SeriesBounds.Top),
+ Right = chart.PointToValue(xAxis, (float)chart.SeriesBounds.Right, (float)chart.SeriesBounds.Top),
+ Top = chart.PointToValue(yAxis, (float)chart.SeriesBounds.Left, (float)chart.SeriesBounds.Top),
+ Bottom = chart.PointToValue(yAxis, (float)chart.SeriesBounds.Left, (float)chart.SeriesBounds.Bottom)
+ };
+ }
+
+ ///
+ /// Clamps annotation coordinates to plot area bounds.
+ ///
+ public static void ClampCoordinatesToBounds(ref double x1, ref double x2, ref double y1, ref double y2, PlotAreaBounds bounds)
+ {
+ // Clamp X positions
+ if (x1 < bounds.Left)
+ {
+ var offset = bounds.Left - x1;
+ x1 = bounds.Left;
+ x2 += offset;
+ }
+ if (x2 > bounds.Right)
+ {
+ var offset = x2 - bounds.Right;
+ x2 = bounds.Right;
+ x1 -= offset;
+ }
+
+ // Clamp Y positions
+ if (y1 < bounds.Bottom)
+ {
+ var offset = bounds.Bottom - y1;
+ y1 = bounds.Bottom;
+ y2 += offset;
+ }
+ if (y2 > bounds.Top)
+ {
+ var offset = y2 - bounds.Top;
+ y2 = bounds.Top;
+ y1 -= offset;
+ }
+ }
+
+ ///
+ /// Converts object value to double, handling multiple numeric types.
+ ///
+ public static double ToNumeric(object? value)
+ {
+ return value switch
+ {
+ double d => d,
+ float f => f,
+ int i => i,
+ long l => l,
+ string s => double.TryParse(s, out var result) ? result : 0d,
+ _ => 0d
+ };
+ }
+
+ ///
+ /// Clamps a value between visible min and max with an extend buffer.
+ ///
+ public static double ClampToVisibleRange(double value, double visibleMin, double visibleMax, double extend)
+ {
+ if (value <= visibleMin)
+ return visibleMin + extend;
+ if (value >= visibleMax)
+ return visibleMax - extend;
+ return value;
+ }
+ }
+
+ public sealed class DraggableLineAnnotation : LineAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private ChartAxis? _xAxis;
+ private RangeAxisBase? _yAxis;
+ private bool _isDragging;
+ private double _previousAxisX;
+ private double _previousAxisY;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _xAxis = chart.XAxes.Count > 0 ? chart.XAxes[0] : null;
+ _yAxis = chart.YAxes.Count > 0 ? chart.YAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ var deltaX = axisX - _previousAxisX;
+ var deltaY = axisY - _previousAxisY;
+
+ ApplyDelta(deltaX, deltaY);
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+
+ private void ApplyDelta(double deltaX, double deltaY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var newX1 = DraggableAnnotationHelper.ToNumeric(X1) + deltaX;
+ var newX2 = DraggableAnnotationHelper.ToNumeric(X2) + deltaX;
+ var newY1 = Y1 + deltaY;
+ var newY2 = Y2 + deltaY;
+
+ var bounds = DraggableAnnotationHelper.GetPlotAreaBounds(_chart, _xAxis, _yAxis);
+ DraggableAnnotationHelper.ClampCoordinatesToBounds(ref newX1, ref newX2, ref newY1, ref newY2, bounds);
+
+ X1 = newX1;
+ X2 = newX2;
+ Y1 = newY1;
+ Y2 = newY2;
+ }
+ }
+
+ public sealed class DraggableVerticalLineAnnotation : VerticalLineAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private ChartAxis? _xAxis;
+ private bool _isDragging;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _xAxis = chart.XAxes.Count > 0 ? chart.XAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _xAxis is null)
+ {
+ return;
+ }
+
+ var linePixel = _xAxis.ValueToPoint(Convert.ToDouble(X1));
+ if (double.IsNaN(linePixel))
+ {
+ return;
+ }
+
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _xAxis is null)
+ {
+ return;
+ }
+
+ var newValue = _chart.PointToValue(_xAxis, pointX, pointY);
+ if (double.IsNaN(newValue) || double.IsInfinity(newValue))
+ {
+ return;
+ }
+
+ X1 = DraggableAnnotationHelper.ClampToVisibleRange(newValue, _xAxis.VisibleMinimum, _xAxis.VisibleMaximum, 0.1);
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+ }
+
+ public sealed class DraggableHorizontalLineAnnotation : HorizontalLineAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private RangeAxisBase? _yAxis;
+ private bool _isDragging;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _yAxis = chart.YAxes.Count > 0 ? chart.YAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var linePixel = _yAxis.ValueToPoint(Y1);
+ if (double.IsNaN(linePixel))
+ {
+ return;
+ }
+
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var newValue = _chart.PointToValue(_yAxis, pointX, pointY);
+ if (double.IsNaN(newValue) || double.IsInfinity(newValue))
+ {
+ return;
+ }
+
+ Y1 = DraggableAnnotationHelper.ClampToVisibleRange(newValue, _yAxis.VisibleMinimum, _yAxis.VisibleMaximum, 2);
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+ }
+
+ public sealed class DraggableRectangleAnnotation : RectangleAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private ChartAxis? _xAxis;
+ private RangeAxisBase? _yAxis;
+ private bool _isDragging;
+ private double _previousAxisX;
+ private double _previousAxisY;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _xAxis = chart.XAxes.Count > 0 ? chart.XAxes[0] : null;
+ _yAxis = chart.YAxes.Count > 0 ? chart.YAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ var deltaX = axisX - _previousAxisX;
+ var deltaY = axisY - _previousAxisY;
+
+ ApplyDelta(deltaX, deltaY);
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+
+ private void ApplyDelta(double deltaX, double deltaY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var newX1 = DraggableAnnotationHelper.ToNumeric(X1) + deltaX;
+ var newX2 = DraggableAnnotationHelper.ToNumeric(X2) + deltaX;
+ var newY1 = Y1 + deltaY;
+ var newY2 = Y2 + deltaY;
+
+ var bounds = DraggableAnnotationHelper.GetPlotAreaBounds(_chart, _xAxis, _yAxis);
+ DraggableAnnotationHelper.ClampCoordinatesToBounds(ref newX1, ref newX2, ref newY1, ref newY2, bounds);
+
+ X1 = newX1;
+ X2 = newX2;
+ Y1 = newY1;
+ Y2 = newY2;
+ }
+ }
+
+ public sealed class DraggableEllipseAnnotation : EllipseAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private ChartAxis? _xAxis;
+ private RangeAxisBase? _yAxis;
+ private bool _isDragging;
+ private double _previousAxisX;
+ private double _previousAxisY;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _xAxis = chart.XAxes.Count > 0 ? chart.XAxes[0] : null;
+ _yAxis = chart.YAxes.Count > 0 ? chart.YAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ var deltaX = axisX - _previousAxisX;
+ var deltaY = axisY - _previousAxisY;
+
+ ApplyDelta(deltaX, deltaY);
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+
+ private void ApplyDelta(double deltaX, double deltaY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var newX1 = DraggableAnnotationHelper.ToNumeric(X1) + deltaX;
+ var newX2 = DraggableAnnotationHelper.ToNumeric(X2) + deltaX;
+ var newY1 = Y1 + deltaY;
+ var newY2 = Y2 + deltaY;
+
+ var bounds = DraggableAnnotationHelper.GetPlotAreaBounds(_chart, _xAxis, _yAxis);
+ DraggableAnnotationHelper.ClampCoordinatesToBounds(ref newX1, ref newX2, ref newY1, ref newY2, bounds);
+
+ X1 = newX1;
+ X2 = newX2;
+ Y1 = newY1;
+ Y2 = newY2;
+ }
+ }
+
+ public sealed class DraggableTextAnnotation : TextAnnotation
+ {
+ private Syncfusion.Maui.Toolkit.Charts.SfCartesianChart? _chart;
+ private ChartAxis? _xAxis;
+ private RangeAxisBase? _yAxis;
+ private bool _isDragging;
+ private double _previousAxisX;
+ private double _previousAxisY;
+ private bool _isDragEnabled = false;
+
+ public void SetDragEnabled(bool enabled)
+ {
+ _isDragEnabled = enabled;
+ }
+
+ public void Attach(Syncfusion.Maui.Toolkit.Charts.SfCartesianChart chart)
+ {
+ _chart = chart;
+ _xAxis = chart.XAxes.Count > 0 ? chart.XAxes[0] : null;
+ _yAxis = chart.YAxes.Count > 0 ? chart.YAxes[0] : null;
+ }
+
+ protected override void OnTouchDown(float pointX, float pointY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ _isDragging = _isDragEnabled;
+ }
+
+ protected override void OnTouchMove(float pointX, float pointY)
+ {
+ if (!_isDragging || _chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ var axisX = _chart.PointToValue(_xAxis, pointX, pointY);
+ var axisY = _chart.PointToValue(_yAxis, pointX, pointY);
+
+ if (double.IsNaN(axisX) || double.IsInfinity(axisX) ||
+ double.IsNaN(axisY) || double.IsInfinity(axisY))
+ {
+ return;
+ }
+
+ var deltaX = axisX - _previousAxisX;
+ var deltaY = axisY - _previousAxisY;
+
+ ApplyDelta(deltaX, deltaY);
+ _previousAxisX = axisX;
+ _previousAxisY = axisY;
+ }
+
+ protected override void OnTouchUp(float pointX, float pointY)
+ {
+ _isDragging = false;
+ }
+
+ private void ApplyDelta(double deltaX, double deltaY)
+ {
+ if (_chart is null || _xAxis is null || _yAxis is null)
+ {
+ return;
+ }
+
+ double newX1 = DraggableAnnotationHelper.ToNumeric(X1) + deltaX;
+ double newY1 = Y1 + deltaY;
+ X1 = DraggableAnnotationHelper.ClampToVisibleRange(newX1, _xAxis.VisibleMinimum, _xAxis.VisibleMaximum, 0.3);
+ Y1 = DraggableAnnotationHelper.ClampToVisibleRange(newY1, _yAxis.VisibleMinimum, _yAxis.VisibleMaximum, 0.5);
+ }
+ }
+}
+
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml b/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml
index 457b020e..55369519 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml
+++ b/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml
@@ -3,50 +3,215 @@
x:Class="Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart.ShapeAnnotationSample"
xmlns:local="clr-namespace:Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart"
xmlns:localCore="clr-namespace:Syncfusion.Maui.ControlsGallery;assembly=Syncfusion.Maui.ControlsGallery"
- xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit"
+ xmlns:annotation="clr-namespace:Syncfusion.Maui.ControlsGallery.Samples.CartesianChart.Annotation">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml.cs b/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml.cs
index 640fad9c..027e091c 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml.cs
+++ b/maui/samples/Gallery/Samples/CartesianChart/Annotation/ShapeAnnotationSample.xaml.cs
@@ -1,17 +1,202 @@
+using Syncfusion.Maui.ControlsGallery.Samples.CartesianChart.Annotation;
+using Syncfusion.Maui.Toolkit.Charts;
+
namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
{
public partial class ShapeAnnotationSample : SampleView
{
+ private ChartAnnotation? _selectedAnnotation;
+ private Color _selectedColor = Colors.Blue;
+ private readonly Dictionary _annotationColors = new();
+
public ShapeAnnotationSample()
{
InitializeComponent();
+ verticalLine.Attach(Chart);
+ horizontalLine.Attach(Chart);
+ lineAnnotation.Attach(Chart);
+ rectangleAnnotation.Attach(Chart);
+ ellipseAnnotation.Attach(Chart);
+ textAnnotation.Attach(Chart);
+ }
+
+ private void OnDragDropCheckChanged(object? sender, CheckedChangedEventArgs e)
+ {
+ bool isEnabled = e.Value;
+ EnableDragDrop(isEnabled);
+ if (isEnabled && ChangeColorRadio.IsChecked)
+ {
+ ChangeColorRadio.IsChecked = false;
+ }
+ }
+
+ private void OnChangeColorRadioChanged(object? sender, CheckedChangedEventArgs e)
+ {
+ bool isEnabled = e.Value;
+ ChangeColorRadio.IsChecked = isEnabled;
+ if (isEnabled && DragDropCheckBox.IsChecked)
+ {
+ DragDropCheckBox.IsChecked = false;
+ }
+ }
+
+ private void EnableDragDrop(bool isEnabled)
+ {
+ verticalLine.SetDragEnabled(isEnabled);
+ horizontalLine.SetDragEnabled(isEnabled);
+ lineAnnotation.SetDragEnabled(isEnabled);
+ rectangleAnnotation.SetDragEnabled(isEnabled);
+ ellipseAnnotation.SetDragEnabled(isEnabled);
+ textAnnotation.SetDragEnabled(isEnabled);
+ }
+
+ private void Chart_AnnotationTapped(object? sender, AnnotationTappedEventArgs e)
+ {
+ if (!(ChangeColorRadio?.IsChecked ?? false))
+ return;
+
+ var annotation = e.Annotation;
+ if (annotation is null)
+ return;
+
+ _selectedAnnotation = annotation;
+
+ // Show the overlay first so the palette grid is visible/rendered
+ ColorPickerOverlay.IsVisible = true;
+
+ // Restore the last color used for this annotation after the UI is ready
+ ResetColorSelectionIndicators();
+ if (_annotationColors.TryGetValue(annotation, out var storedColor))
+ {
+ _selectedColor = storedColor;
+ Dispatcher.Dispatch(() => HighlightStoredColor(storedColor));
+ }
+ else
+ {
+ // No prior color — clear any leftover selection
+ _selectedColor = Colors.Blue;
+ }
+ }
+
+ private void OnApplyColorClicked(object? sender, EventArgs e)
+ {
+ if (_selectedAnnotation != null)
+ _annotationColors[_selectedAnnotation] = _selectedColor;
+
+ ApplyColorToAnnotation();
+ ColorPickerOverlay.IsVisible = false;
+ _selectedAnnotation = null;
+ }
+ private void OnCloseTapped(object? sender, TappedEventArgs e)
+ {
+ ColorPickerOverlay.IsVisible = false;
+ _selectedAnnotation = null;
+ }
+ private void ApplyColorToAnnotation()
+ {
+ if (_selectedAnnotation == null)
+ {
+ return;
+ }
+
+ Color color = _selectedColor;
+ SolidColorBrush brush = new(color);
+ if (_selectedAnnotation is DraggableLineAnnotation lineAnn)
+ {
+ lineAnn.Stroke = brush;
+ }
+ else if (_selectedAnnotation is DraggableHorizontalLineAnnotation hLineAnn)
+ {
+ hLineAnn.Stroke = brush;
+ }
+ else if (_selectedAnnotation is DraggableVerticalLineAnnotation vLineAnn)
+ {
+ vLineAnn.Stroke = brush;
+ }
+ else if (_selectedAnnotation is DraggableRectangleAnnotation rectAnn)
+ {
+ rectAnn.Fill = brush;
+ }
+ else if (_selectedAnnotation is DraggableEllipseAnnotation ellipseAnn)
+ {
+ ellipseAnn.Fill = brush;
+ }
+ else if (_selectedAnnotation is DraggableTextAnnotation textAnn)
+ {
+ textAnn.LabelStyle = new ChartAnnotationLabelStyle
+ {
+ TextColor = color
+ };
+ }
+ }
+
+ private void OnColorPickerClosed(object? sender, EventArgs e)
+ {
+ ColorPickerOverlay.IsVisible = false;
+ _selectedAnnotation = null;
+ }
+
+ private void OnColorOptionTapped(object? sender, TappedEventArgs e)
+ {
+ // Get the hex color code from the command parameter
+ if (e.Parameter is string hexColor)
+ {
+ try
+ {
+ _selectedColor = Color.FromArgb(hexColor);
+
+ // Update the visual selection indicator
+ ResetColorSelectionIndicators();
+
+ // sender is the BoxView, get its parent Border
+ if (sender is BoxView boxView && boxView.Parent is Border border)
+ {
+ border.Stroke = Colors.Black;
+ border.StrokeThickness = 2;
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"Error parsing color: {hexColor}, Exception: {ex.Message}");
+ }
+ }
+ }
+
+ private void HighlightStoredColor(Color color)
+ {
+ var paletteGrid = this.FindByName("ColorPaletteGrid") as Grid;
+ if (paletteGrid == null)
+ return;
+
+ foreach (var child in paletteGrid.Children)
+ {
+ if (child is Border border && border.Content is BoxView boxView)
+ {
+ if (boxView.Color.ToString() == color.ToString())
+ {
+ border.Stroke = Colors.Black;
+ border.StrokeThickness = 2;
+ break;
+ }
+ }
+ }
}
- public override void OnDisappearing()
+ private void ResetColorSelectionIndicators()
{
- base.OnDisappearing();
- //Chart.Handler?.DisconnectHandler();
+ var paletteGrid = this.FindByName("ColorPaletteGrid") as Grid;
+ if (paletteGrid != null)
+ {
+ foreach (var child in paletteGrid.Children)
+ {
+ if (child is Border border)
+ {
+ border.Stroke = Colors.Transparent;
+ border.StrokeThickness = 2;
+ }
+ }
+ }
}
}
-}
\ No newline at end of file
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml
new file mode 100644
index 00000000..f270720d
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml.cs b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml.cs
new file mode 100644
index 00000000..0ae47636
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHair.xaml.cs
@@ -0,0 +1,39 @@
+using Syncfusion.Maui.Toolkit.Charts;
+
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
+{
+ public partial class CartesianCrossHair : SampleView
+ {
+ int _month = int.MaxValue;
+
+ public CartesianCrossHair()
+ {
+ InitializeComponent();
+ }
+
+ // X axis label formatting logic
+ private void Primary_LabelCreated(object sender, Syncfusion.Maui.Toolkit.Charts.ChartAxisLabelEventArgs e)
+ {
+ DateTime baseDate = new(2024, 09, 16);
+ var date = baseDate.AddDays(e.Position);
+ if (date.Month != _month)
+ {
+ ChartAxisLabelStyle labelStyle = new()
+ {
+ LabelFormat = "MMM-dd",
+ FontAttributes = FontAttributes.Bold
+ };
+ e.LabelStyle = labelStyle;
+ _month = date.Month;
+ }
+ else
+ {
+ ChartAxisLabelStyle labelStyle = new()
+ {
+ LabelFormat = "dd"
+ };
+ e.LabelStyle = labelStyle;
+ }
+ }
+ }
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHairViewModel.cs b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHairViewModel.cs
new file mode 100644
index 00000000..ef0ee575
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/CrossHair/CartesianCrossHairViewModel.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
+{
+ public class CartesianCrossHairViewModel : BaseViewModel
+ {
+ public ObservableCollection StockPrices { get; private set; } = new ObservableCollection();
+ public ObservableCollection VolumeUp { get; private set; } = new ObservableCollection();
+ public ObservableCollection VolumeDown { get; private set; } = new ObservableCollection();
+ public DateTime MinDate { get; private set; }
+ public DateTime MaxDate { get; private set; }
+
+ private const string CsvData = @"7/1/2025,496.47,498.05,490.98,492.05,59955291
+ 7/2/2025,489.99,493.5,488.7,491.09,59011824
+ 7/3/2025,493.81,500.13,493.44,498.84,59377455
+ 7/7/2025,497.38,498.75,495.23,497.72,59866198
+ 7/8/2025,497.24,498.2,494.11,496.62,59055210
+ 7/9/2025,500.3,506.78,499.74,503.51,59277261
+ 7/10/2025,503.05,504.44,497.75,501.48,59499244
+ 7/11/2025,498.47,505.03,497.8,503.32,59666177
+ 7/14/2025,501.52,503.97,501.03,503.02,59988412
+ 7/15/2025,503.02,508.3,502.79,505.82,59744990
+ 7/16/2025,505.18,506.72,501.89,505.62,59299283
+ 7/17/2025,505.68,513.37,505.62,511.7,59655166
+ 7/18/2025,514.48,514.64,507.43,510.05,59077340
+ 7/21/2025,506.71,512.09,505.55,510.06,59899215
+ 7/22/2025,510.97,511.2,505.27,505.27,59477039
+ 7/23/2025,506.75,506.79,500.7,505.87,59333618
+ 7/24/2025,508.77,513.67,507.3,510.88,59755102
+ 7/25/2025,512.47,518.29,510.36,513.71,59588791
+ 7/28/2025,514.08,515.0,510.12,512.5,59922044
+ 7/29/2025,515.53,517.62,511.56,512.57,59677192
+ 7/30/2025,515.17,515.95,509.44,513.24,59411388
+ 7/31/2025,555.23,555.45,531.9,533.5,59266077
+ 8/1/2025,535.0,535.8,520.86,524.11,59929944
+ 8/4/2025,528.27,538.25,528.13,535.64,59088201
+ 8/5/2025,537.18,537.3,527.24,527.75,59800672
+ 8/6/2025,530.9,531.7,524.03,524.94,59399128
+ 8/7/2025,526.8,528.09,517.55,520.84,59766177
+ 8/8/2025,522.6,524.66,519.41,522.04,59977411
+ 8/11/2025,522.3,527.59,519.72,521.77,59622831
+ 8/12/2025,523.75,530.98,522.7,529.24,59555019
+ 8/13/2025,532.11,532.7,519.37,520.58,59444892
+ 8/14/2025,522.56,525.95,520.14,522.48,59399277
+ 8/15/2025,522.77,526.1,519.08,520.17,59866055
+ 8/18/2025,521.59,522.82,514.02,517.1,59977531
+ 8/19/2025,515.0,515.16,508.55,509.77,59033101
+ 8/20/2025,509.87,511.0,504.44,505.72,59900519
+ 8/21/2025,503.69,507.63,502.72,504.24,59188255
+ 8/22/2025,504.25,510.73,502.41,507.23,59399177
+ 8/25/2025,506.63,508.19,504.12,504.26,59400711
+ 8/26/2025,504.36,504.98,498.51,502.04,59877344
+ 8/27/2025,502.0,507.29,499.9,506.74,59266219
+ 8/28/2025,507.09,511.09,505.5,509.64,60000000
+ 8/29/2025,508.66,509.6,504.49,506.69,59166230
+ 9/2/2025,500.47,506.0,496.81,505.12,59355108
+ 9/3/2025,503.79,507.79,502.32,505.35,59844199
+ 9/4/2025,504.3,508.15,503.15,507.97,59177201
+ 9/5/2025,509.07,511.97,492.37,495.0,59299340
+ 9/8/2025,498.11,501.2,495.03,498.2,59488512
+ 9/9/2025,501.43,502.25,497.7,498.41,59922733
+ 9/10/2025,502.98,503.23,496.72,500.37,59066519
+ 9/11/2025,502.25,503.17,497.88,501.01,59188922
+ 9/12/2025,506.65,512.55,503.85,509.9,59900518
+ 9/15/2025,508.79,515.47,507.0,515.36,59377530
+ 9/16/2025,516.88,517.23,508.6,509.04,59499172
+ 9/17/2025,510.62,511.29,505.93,510.02,60000000
+ 9/18/2025,511.49,513.07,507.66,508.45,59822755
+ 9/19/2025,510.56,519.3,510.31,517.93,59366101
+ 9/22/2025,515.59,517.74,512.55,514.45,59977259
+ 9/23/2025,513.8,514.59,507.31,509.23,59755133
+ 9/24/2025,510.38,512.48,506.92,510.15,59188166
+ 9/25/2025,508.3,510.01,505.04,507.03,59300522
+ 9/26/2025,510.06,513.94,506.62,511.46,59911388
+ 9/29/2025,511.5,516.85,508.88,514.6,59277194
+ 9/30/2025,513.24,518.16,509.66,517.95,59666255
+ 10/1/2025,514.8,520.51,511.69,519.71,59900517
+ 10/2/2025,517.64,521.6,510.68,515.74,59011998
+ 10/3/2025,517.1,520.49,515.0,517.35,59888211
+ 10/6/2025,518.61,531.03,518.2,528.57,59644077
+ 10/7/2025,528.29,529.8,521.44,523.98,59577215
+ 10/8/2025,523.28,526.95,523.09,524.85,59322914
+ 10/9/2025,522.34,524.33,517.4,522.4,59955009
+ 10/10/2025,519.64,523.58,509.63,510.96,59166122
+ 10/13/2025,516.41,516.41,511.68,514.05,59977193
+ 10/14/2025,510.23,515.28,506.0,513.57,59855011
+ 10/15/2025,514.96,517.19,510.0,513.43,59466104
+ 10/16/2025,512.58,516.85,508.13,511.61,59799213
+ 10/17/2025,509.04,515.48,507.31,513.58,59588277
+ 10/20/2025,514.61,518.7,513.43,516.79,59877451
+ 10/21/2025,517.5,518.69,513.04,517.66,59455718
+ 10/22/2025,521.15,525.23,517.71,520.54,59912316
+ 10/23/2025,522.46,523.95,518.61,520.56,59200832
+ 10/24/2025,522.79,525.35,520.71,523.61,59899144
+ 10/27/2025,531.78,534.58,529.01,531.52,59566003
+ 10/28/2025,550.0,553.72,540.77,542.07,59288511
+ 10/29/2025,544.94,546.27,536.73,541.55,59999128
+ 10/30/2025,530.48,534.97,522.12,525.76,59855991
+ 10/31/2025,528.88,529.32,515.1,517.81,59688260
+ 11/3/2025,519.81,524.96,514.59,517.03,59333178
+ 11/4/2025,511.76,515.55,507.84,514.33,59877422
+ 11/5/2025,513.3,514.83,506.58,507.16,59955013
+ 11/6/2025,505.66,505.7,495.81,497.1,59288211
+ 11/7/2025,496.95,499.38,493.25,496.82,59466177
+ 11/10/2025,500.04,506.85,498.8,506.0,59055831
+ 11/11/2025,504.8,509.6,502.35,508.68,59833102
+ 11/12/2025,509.36,511.67,499.12,511.14,59444918
+ 11/13/2025,510.31,513.5,501.29,503.29,60000000
+ 11/14/2025,498.23,511.6,497.44,510.18,59288265
+ 11/17/2025,508.45,512.12,504.91,507.49,59966103
+ 11/18/2025,495.37,502.98,486.78,493.79,59800677
+ 11/19/2025,490.1,495.19,482.83,487.12,59277451
+ 11/20/2025,492.71,493.57,475.5,478.43,59988177
+ 11/21/2025,478.5,478.92,468.27,472.12,59400752
+ 11/24/2025,475.0,476.9,468.02,474.0,59866114
+ 11/25/2025,474.07,479.15,464.89,476.99,59255027
+ 11/26/2025,486.31,488.31,481.2,485.5,59777149
+ 11/28/2025,487.6,492.63,486.65,492.01,59922833
+ 12/1/2025,488.44,489.86,484.65,486.74,59866177
+ 12/2/2025,486.72,493.5,486.32,490.0,59188294
+ 12/3/2025,476.32,484.24,475.2,477.73,59355101
+ 12/4/2025,479.76,481.32,476.49,480.84,59688231
+ 12/5/2025,482.52,483.4,478.88,483.16,59477019
+ 12/8/2025,484.89,492.3,484.38,491.02,59055077
+ 12/9/2025,489.1,492.12,488.5,492.02,59899166
+ 12/10/2025,484.03,484.25,475.08,478.56,59733519
+ 12/11/2025,476.63,486.03,475.86,483.47,59466105
+ 12/12/2025,479.82,482.45,476.34,478.53,59277412
+ 12/15/2025,480.1,480.72,472.52,474.82,59655990
+ 12/16/2025,471.91,477.89,470.88,476.39,59199144
+ 12/17/2025,476.91,480.0,475.0,476.11,59977122
+ 12/18/2025,478.19,489.6,477.89,483.98,59622744
+ 12/19/2025,487.36,487.85,482.49,485.92,59433771
+ 12/22/2025,486.12,488.73,482.69,484.92,59999106
+ 12/23/2025,484.98,487.83,484.74,486.85,59555128
+ 12/24/2025,485.68,489.16,484.83,488.02,59377290
+ 12/26/2025,486.71,488.12,485.96,487.71,59866011
+ 12/29/2025,484.86,488.35,484.18,487.1,59977155
+ 12/30/2025,485.93,489.68,485.5,487.48,59400771
+ 12/31/2025,487.84,488.14,483.3,483.62,59522990";
+
+ public CartesianCrossHairViewModel()
+ {
+ var data = LoadCsvFromString(CsvData);
+
+ var ordered = data
+ .GroupBy(d => d.Date.Date)
+ .Select(g => g.First())
+ .OrderBy(d => d.Date)
+ .ToList();
+
+ StockPrices = new ObservableCollection(ordered);
+ var up = new List(ordered.Count);
+ var down = new List(ordered.Count);
+ foreach (var it in ordered)
+ {
+ bool isUp = it.Size >= it.Value;
+ var upVol = isUp ? it.Volume : 0d;
+ var dnVol = isUp ? 0d : it.Volume;
+
+ up.Add(new ChartDataModel(it.Date, it.Value, it.High, it.Low, it.Size, upVol));
+ down.Add(new ChartDataModel(it.Date, it.Value, it.High, it.Low, it.Size, dnVol));
+ }
+
+ VolumeUp = new ObservableCollection(up);
+ VolumeDown = new ObservableCollection(down);
+
+ if (ordered.Count > 0)
+ {
+ MinDate = ordered.First().Date.Date;
+ MaxDate = ordered.Last().Date.Date;
+ }
+ }
+
+
+ private static List LoadCsvFromString(string csvData)
+ {
+ var items = new List();
+ var lines = csvData.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ var formats = new[] { "M/d/yyyy", "MM/dd/yyyy"};
+
+ foreach (var line in lines)
+ {
+ if (string.IsNullOrWhiteSpace(line)) continue;
+ var parts = line.Split(',');
+ if (parts.Length < 6) continue;
+ if (parts[0].Trim().Equals("date", StringComparison.OrdinalIgnoreCase)) continue;
+ if (!DateTime.TryParseExact(parts[0].Trim(), formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) continue;
+
+#if ANDROID || IOS
+ if (!(date.Month >= 10 && date.Month <= 12))
+ continue;
+#endif
+
+ if (!double.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var low)) continue;
+ if (!double.TryParse(parts[2], NumberStyles.Any, CultureInfo.InvariantCulture, out var high)) continue;
+ if (!double.TryParse(parts[3], NumberStyles.Any, CultureInfo.InvariantCulture, out var open)) continue;
+ if (!double.TryParse(parts[4], NumberStyles.Any, CultureInfo.InvariantCulture, out var close)) continue;
+ if (!double.TryParse(parts[5], NumberStyles.Any, CultureInfo.InvariantCulture, out var vol)) continue;
+ items.Add(new ChartDataModel(date.Date, open, high, low, close, vol / 150_000d));
+ }
+
+ return items;
+ }
+ }
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/FastScatterChart/FastScatterChart.xaml b/maui/samples/Gallery/Samples/CartesianChart/FastScatterChart/FastScatterChart.xaml
index 8a86eb52..97db5e39 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/FastScatterChart/FastScatterChart.xaml
+++ b/maui/samples/Gallery/Samples/CartesianChart/FastScatterChart/FastScatterChart.xaml
@@ -43,13 +43,17 @@
XBindingPath="Value"
YBindingPath="Size"
EnableTooltip="True"
- Label="Train travel"/>
+ Label="Train travel"
+ PointHeight="{OnPlatform MacCatalyst='8'}"
+ PointWidth="{OnPlatform MacCatalyst='8'}"/>
+ Label="Automobile travel"
+ PointHeight="{OnPlatform MacCatalyst='8'}"
+ PointWidth="{OnPlatform MacCatalyst='8'}"/>
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml b/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml
index cfea915e..b8194c51 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml
+++ b/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml
@@ -7,151 +7,198 @@
xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit"
xmlns:core="clr-namespace:Syncfusion.Maui.Toolkit;assembly=Syncfusion.Maui.Toolkit"
x:DataType="local:LegendViewModel">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml.cs b/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml.cs
index 8044f88f..3a485f89 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml.cs
+++ b/maui/samples/Gallery/Samples/CartesianChart/Legend/CartesianLegend.xaml.cs
@@ -1,4 +1,5 @@
using Microsoft.Maui.Controls.Shapes;
+using Syncfusion.Maui.Toolkit;
using Syncfusion.Maui.Toolkit.Charts;
namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
@@ -15,6 +16,109 @@ public override void OnDisappearing()
base.OnDisappearing();
tooltipChart.Handler?.DisconnectHandler();
}
+
+ private void FloatingLegend_CheckedChanged(object? sender, CheckedChangedEventArgs e)
+ {
+ if (sender is not CheckBox checkBox || CartesianChartLegend is null)
+ return;
+
+ CartesianChartLegend.IsFloating = checkBox.IsChecked;
+ if (xOffsetStepperLabel != null)
+ {
+ xOffsetStepperLabel.IsEnabled = checkBox.IsChecked;
+ xOffsetStepperLabel.Opacity = checkBox.IsChecked ? 1 : 0.5;
+ }
+ if (xOffsetStepper != null)
+ {
+ xOffsetStepper.IsEnabled = checkBox.IsChecked;
+ xOffsetStepper.Opacity = checkBox.IsChecked ? 1 : 0.5;
+ }
+ if (yOffsetStepperLabel != null)
+ {
+ yOffsetStepperLabel.IsEnabled = checkBox.IsChecked;
+ yOffsetStepperLabel.Opacity = checkBox.IsChecked ? 1 : 0.5;
+ }
+ if (yOffsetStepper != null)
+ {
+ yOffsetStepper.IsEnabled = checkBox.IsChecked;
+ yOffsetStepper.Opacity = checkBox.IsChecked ? 1 : 0.5;
+ }
+ }
+
+ private void Picker_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (sender is not Microsoft.Maui.Controls.Picker value || CartesianChartLegend is null)
+ return;
+
+ int selectedIndex = value.SelectedIndex;
+ if (selectedIndex == 0)
+ {
+ CartesianChartLegend.Placement = LegendPlacement.Top;
+ }
+ else if (selectedIndex == 1)
+ {
+ CartesianChartLegend.Placement = LegendPlacement.Left;
+ }
+ else if (selectedIndex == 2)
+ {
+ CartesianChartLegend.Placement = LegendPlacement.Bottom;
+ }
+ else if (selectedIndex == 3)
+ {
+ CartesianChartLegend.Placement = LegendPlacement.Right;
+ }
+ }
+
+ int xOffset = 0;
+ int yOffset = 0;
+
+ private void OnXIncrementClicked(object? sender, EventArgs e)
+ {
+ if (xOffset < 100)
+ {
+ xOffset += 10;
+ if (xOffsetValue != null)
+ xOffsetValue.Text = xOffset.ToString();
+ if (CartesianChartLegend != null)
+ CartesianChartLegend.OffsetX = xOffset;
+ }
+ }
+
+ private void OnXDecrementClicked(object? sender, EventArgs e)
+ {
+ if (xOffset > -100)
+ {
+ xOffset -= 10;
+ if (xOffsetValue != null)
+ xOffsetValue.Text = xOffset.ToString();
+ if (CartesianChartLegend != null)
+ CartesianChartLegend.OffsetX = xOffset;
+ }
+ }
+
+ private void OnYIncrementClicked(object? sender, EventArgs e)
+ {
+ if (yOffset < 100)
+ {
+ yOffset += 10;
+ if (yOffsetValue != null)
+ yOffsetValue.Text = yOffset.ToString();
+ if (CartesianChartLegend != null)
+ CartesianChartLegend.OffsetY = yOffset;
+ }
+ }
+
+ private void OnYDecrementClicked(object? sender, EventArgs e)
+ {
+ if (yOffset > -100)
+ {
+ yOffset -= 10;
+ if (yOffsetValue != null)
+ yOffsetValue.Text = yOffset.ToString();
+ if (CartesianChartLegend != null)
+ CartesianChartLegend.OffsetY = yOffset;
+ }
+ }
}
public partial class LineSeriesExt : LineSeries
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Legend/LegendViewModel.cs b/maui/samples/Gallery/Samples/CartesianChart/Legend/LegendViewModel.cs
index bbc3d953..b5ffa075 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/Legend/LegendViewModel.cs
+++ b/maui/samples/Gallery/Samples/CartesianChart/Legend/LegendViewModel.cs
@@ -4,6 +4,7 @@ namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
{
public partial class LegendViewModel : BaseViewModel
{
+ public string[] LegendPositionType => ["Top", "Left", "Bottom", "Right"];
public ObservableCollection ChartData1 { get; set; }
public ObservableCollection ChartData2 { get; set; }
public ObservableCollection ChartData3 { get; set; }
diff --git a/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml
new file mode 100644
index 00000000..dea979fb
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml.cs b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml.cs
new file mode 100644
index 00000000..9cbecb93
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorCustomization.xaml.cs
@@ -0,0 +1,16 @@
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
+{
+ public partial class PointColorCustomization : SampleView
+ {
+ public PointColorCustomization()
+ {
+ InitializeComponent();
+ }
+
+ public override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ chart.Handler?.DisconnectHandler();
+ }
+ }
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorViewModel.cs b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorViewModel.cs
new file mode 100644
index 00000000..b919c3de
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/PointColorMapping/PointColorViewModel.cs
@@ -0,0 +1,28 @@
+using System.Collections.ObjectModel;
+
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
+{
+ public class PointColorViewModel : BaseViewModel
+ {
+ public ObservableCollection TemperatureData { get; set; }
+
+ public PointColorViewModel()
+ {
+ TemperatureData = new ObservableCollection
+ {
+ new() { Name = "Jan", Value = 42, PointColor = Color.FromArgb("#E6CDF9") },
+ new() { Name = "Feb", Value = 45, PointColor = Color.FromArgb("#D1A8F3") },
+ new() { Name = "Mar", Value = 53, PointColor = Color.FromArgb("#BB83EC") },
+ new() { Name = "Apr", Value = 59, PointColor = Color.FromArgb("#A35DE5") },
+ new() { Name = "May", Value = 64, PointColor = Color.FromArgb("#8933DE") },
+ new() { Name = "Jun", Value = 72, PointColor = Color.FromArgb("#6621AC") },
+ new() { Name = "Jul", Value = 73, PointColor = Color.FromArgb("#551E8B") },
+ new() { Name = "Aug", Value = 71, PointColor = Color.FromArgb("#7923CE") },
+ new() { Name = "Sep", Value = 65, PointColor = Color.FromArgb("#9649E2") },
+ new() { Name = "Oct", Value = 58, PointColor = Color.FromArgb("#AF70E9") },
+ new() { Name = "Nov", Value = 52, PointColor = Color.FromArgb("#C695F0") },
+ new() { Name = "Dec", Value = 50, PointColor = Color.FromArgb("#DCBBF6") }
+ };
+ }
+ }
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml b/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml
new file mode 100644
index 00000000..1d906143
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml.cs b/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml.cs
new file mode 100644
index 00000000..a28b2847
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/Trendline/Trendline.xaml.cs
@@ -0,0 +1,120 @@
+using System.ComponentModel;
+using Syncfusion.Maui.Toolkit.Charts;
+
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart;
+
+public partial class Trendlines : SampleView
+{
+ ChartTrendline? _currentTrendline;
+ TrendlineViewModel? _viewModel;
+
+ public Trendlines()
+ {
+ InitializeComponent();
+ AttachViewModel(BindingContext as TrendlineViewModel);
+ BindingContextChanged += OnBindingContextChanged;
+ }
+
+ void OnBindingContextChanged(object? sender, EventArgs e)
+ {
+ AttachViewModel(BindingContext as TrendlineViewModel);
+ }
+
+ void AttachViewModel(TrendlineViewModel? newViewModel)
+ {
+ if (_viewModel != null)
+ {
+ _viewModel.PropertyChanged -= OnViewModelPropertyChanged;
+ }
+
+ _viewModel = newViewModel;
+
+ if (_viewModel != null)
+ {
+ _viewModel.PropertyChanged += OnViewModelPropertyChanged;
+ UpdateTrendline();
+ }
+ }
+
+ void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(TrendlineViewModel.SelectedTrendlineType))
+ {
+ UpdateTrendline();
+ }
+ }
+
+ void UpdateTrendline()
+ {
+ if (RevenueSeries == null || _viewModel == null)
+ {
+ return;
+ }
+
+ RevenueSeries.Trendlines.Clear();
+
+ var trendline = CreateTrendline(_viewModel.SelectedTrendlineType);
+ trendline.BindingContext = _viewModel;
+ ApplyCommonBindings(trendline);
+
+ RevenueSeries.Trendlines.Add(trendline);
+ _currentTrendline = trendline;
+ }
+
+ ChartTrendline CreateTrendline(string type)
+ {
+ ChartTrendline trendline = type switch
+ {
+ TrendlineViewModel.ExponentialType => new ExponentialTrendline(),
+ TrendlineViewModel.PowerType => new PowerTrendline(),
+ TrendlineViewModel.PolynomialType => new PolynomialTrendline(),
+ TrendlineViewModel.MovingAverageType => new MovingAverageTrendline(),
+ TrendlineViewModel.LogarithmicType => new LogarithmicTrendline(),
+ _ => new LinearTrendline()
+ };
+
+ trendline.Label = "Trend";
+ trendline.Stroke = new SolidColorBrush(Color.FromArgb("#1A73E8"));
+ return trendline;
+ }
+
+ void ApplyCommonBindings(ChartTrendline trendline)
+ {
+ if (_viewModel == null)
+ {
+ return;
+ }
+
+ trendline.SetBinding(ChartTrendline.ShowMarkersProperty,
+ new Binding(nameof(TrendlineViewModel.ShowMarkers)));
+ trendline.SetBinding(ChartTrendline.EnableTooltipProperty,
+ new Binding(nameof(TrendlineViewModel.EnableTrendlineTooltip)));
+ trendline.SetBinding(ChartTrendline.ForwardForecastProperty,
+ new Binding(nameof(TrendlineViewModel.ForwardForecast)));
+ trendline.SetBinding(ChartTrendline.BackwardForecastProperty,
+ new Binding(nameof(TrendlineViewModel.BackwardForecast)));
+ trendline.SetBinding(ChartTrendline.IsVisibleProperty,
+ new Binding(nameof(TrendlineViewModel.IsTrendlineVisible), mode: BindingMode.TwoWay));
+
+ var markerSettings = new ChartMarkerSettings
+ {
+ Fill = new SolidColorBrush(Color.FromArgb("#CFE2FF")),
+ Stroke = new SolidColorBrush(Color.FromArgb("#1A73E8")),
+ StrokeWidth = 2,
+ Type = ShapeType.Diamond
+ };
+ markerSettings.BindingContext = _viewModel;
+ trendline.MarkerSettings = markerSettings;
+
+ if (trendline is PolynomialTrendline polynomialTrendline)
+ {
+ polynomialTrendline.SetBinding(PolynomialTrendline.OrderProperty,
+ new Binding(nameof(TrendlineViewModel.PolynomialOrder)));
+ }
+ else if (trendline is MovingAverageTrendline movingAverageTrendline)
+ {
+ movingAverageTrendline.SetBinding(MovingAverageTrendline.PeriodProperty,
+ new Binding(nameof(TrendlineViewModel.MovingAveragePeriod)));
+ }
+ }
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/Trendline/TrendlineViewModel.cs b/maui/samples/Gallery/Samples/CartesianChart/Trendline/TrendlineViewModel.cs
new file mode 100644
index 00000000..ac3f0fad
--- /dev/null
+++ b/maui/samples/Gallery/Samples/CartesianChart/Trendline/TrendlineViewModel.cs
@@ -0,0 +1,214 @@
+
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Windows.Input;
+
+namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart;
+
+public class TrendlineViewModel : INotifyPropertyChanged
+{
+ public const string LinearType = "Linear";
+ public const string ExponentialType = "Exponential";
+ public const string PowerType = "Power";
+ public const string PolynomialType = "Polynomial";
+ public const string MovingAverageType = "MovingAvg";
+ public const string LogarithmicType = "Logarithmic";
+
+ private const int PolyMin = 2, PolyMax = 6;
+ private const int PeriodMin = 2, PeriodMax = 6;
+
+ private const int ForecastMin = 0, ForecastMax = 6;
+
+ public ObservableCollection QuarterlyRevenue { get; } = new()
+ {
+ new QuarterRevenue(2018, 640),
+ new QuarterRevenue(2019, 705),
+ new QuarterRevenue(2020, 665),
+ new QuarterRevenue(2021, 740),
+ new QuarterRevenue(2022, 710),
+ new QuarterRevenue(2023, 785),
+ new QuarterRevenue(2024, 760),
+ new QuarterRevenue(2025, 845)
+ };
+
+ public IList TrendlineTypes { get; } =
+ new List { LinearType, ExponentialType, PowerType, PolynomialType, MovingAverageType, LogarithmicType };
+
+ bool _isTrendlineVisible = true;
+ public bool IsTrendlineVisible
+ {
+ get => _isTrendlineVisible;
+ set => SetField(ref _isTrendlineVisible, value);
+ }
+
+ bool _showMarkers = true;
+ public bool ShowMarkers
+ {
+ get => _showMarkers;
+ set => SetField(ref _showMarkers, value);
+ }
+
+ bool _enableTrendlineTooltip = true;
+ public bool EnableTrendlineTooltip
+ {
+ get => _enableTrendlineTooltip;
+ set => SetField(ref _enableTrendlineTooltip, value);
+ }
+
+ string _selectedTrendlineType = LinearType;
+ public string SelectedTrendlineType
+ {
+ get => _selectedTrendlineType;
+ set
+ {
+ if (SetField(ref _selectedTrendlineType, value))
+ {
+ OnPropertyChanged(nameof(IsPolynomialVisible));
+ OnPropertyChanged(nameof(IsMovingAverageVisible));
+ }
+ }
+ }
+
+ public bool IsPolynomialVisible => SelectedTrendlineType == PolynomialType;
+ public bool IsMovingAverageVisible => SelectedTrendlineType == MovingAverageType;
+
+ int _polynomialOrder = 3;
+ public int PolynomialOrder
+ {
+ get => _polynomialOrder;
+ set
+ {
+ if (SetField(ref _polynomialOrder, Clamp(value, PolyMin, PolyMax)))
+ RaiseStepperCanExecutes();
+ }
+ }
+
+ int _movingAveragePeriod = 4;
+ public int MovingAveragePeriod
+ {
+ get => _movingAveragePeriod;
+ set
+ {
+ if (SetField(ref _movingAveragePeriod, Clamp(value, PeriodMin, PeriodMax)))
+ RaiseStepperCanExecutes();
+ }
+ }
+
+ int forwardForecast;
+ public int ForwardForecast
+ {
+ get => forwardForecast;
+ set
+ {
+ if (SetField(ref forwardForecast, Clamp(value, ForecastMin, ForecastMax)))
+ RaiseStepperCanExecutes();
+ }
+ }
+
+ int _backwardForecast;
+ public int BackwardForecast
+ {
+ get => _backwardForecast;
+ set
+ {
+ if (SetField(ref _backwardForecast, Clamp(value, ForecastMin, ForecastMax)))
+ RaiseStepperCanExecutes();
+ }
+ }
+
+ public ICommand IncrementForwardCommand { get; }
+ public ICommand DecrementForwardCommand { get; }
+ public ICommand IncrementBackwardCommand { get; }
+ public ICommand DecrementBackwardCommand { get; }
+
+ public ICommand IncrementPolynomialOrderCommand => _incrementPolynomialOrderCommand;
+ public ICommand DecrementPolynomialOrderCommand => _decrementPolynomialOrderCommand;
+
+ public ICommand IncrementMAPeriodCommand => _incrementMAPeriodCommand;
+ public ICommand DecrementMAPeriodCommand => _decrementMAPeriodCommand;
+
+ private readonly RelayCommand _incrementPolynomialOrderCommand;
+ private readonly RelayCommand _decrementPolynomialOrderCommand;
+
+ private readonly RelayCommand _incrementMAPeriodCommand;
+ private readonly RelayCommand _decrementMAPeriodCommand;
+
+ public TrendlineViewModel()
+ {
+ IncrementForwardCommand = new RelayCommand(() => ForwardForecast = Math.Min(ForwardForecast + 1, ForecastMax));
+ DecrementForwardCommand = new RelayCommand(() => ForwardForecast = Math.Max(ForwardForecast - 1, ForecastMin));
+ IncrementBackwardCommand = new RelayCommand(() => BackwardForecast = Math.Min(BackwardForecast + 1, ForecastMax));
+ DecrementBackwardCommand = new RelayCommand(() => BackwardForecast = Math.Max(BackwardForecast - 1, ForecastMin));
+
+ _incrementPolynomialOrderCommand = new RelayCommand(
+ () => PolynomialOrder += 1,
+ () => PolynomialOrder < PolyMax);
+
+ _decrementPolynomialOrderCommand = new RelayCommand(
+ () => PolynomialOrder -= 1,
+ () => PolynomialOrder > PolyMin);
+
+ _incrementMAPeriodCommand = new RelayCommand(
+ () => MovingAveragePeriod += 1,
+ () => MovingAveragePeriod < PeriodMax);
+
+ _decrementMAPeriodCommand = new RelayCommand(
+ () => MovingAveragePeriod -= 1,
+ () => MovingAveragePeriod > PeriodMin);
+ }
+
+ private static int Clamp(int value, int min, int max) =>
+ Math.Max(min, Math.Min(max, value));
+
+ private static double Clamp(double value, double min, double max) =>
+ Math.Max(min, Math.Min(max, value));
+
+ private void RaiseStepperCanExecutes()
+ {
+ _incrementPolynomialOrderCommand?.RaiseCanExecuteChanged();
+ _decrementPolynomialOrderCommand?.RaiseCanExecuteChanged();
+
+ _incrementMAPeriodCommand?.RaiseCanExecuteChanged();
+ _decrementMAPeriodCommand?.RaiseCanExecuteChanged();
+
+ }
+
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
+ bool SetField(ref T storage, T value, [CallerMemberName] string? propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(storage, value))
+ return false;
+
+ storage = value;
+ OnPropertyChanged(propertyName);
+ return true;
+ }
+}
+
+public record QuarterRevenue(double Year, double Revenue);
+
+public sealed class RelayCommand : ICommand
+{
+ readonly Action _execute;
+ readonly Func? _canExecute;
+
+ public RelayCommand(Action execute, Func? canExecute = null)
+ {
+ this._execute = execute;
+ this._canExecute = canExecute;
+ }
+
+ public event EventHandler? CanExecuteChanged;
+
+ public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true;
+
+ public void Execute(object? parameter) => _execute();
+
+ public void RaiseCanExecuteChanged() =>
+ CanExecuteChanged?.Invoke(this, EventArgs.Empty);
+}
diff --git a/maui/samples/Gallery/Samples/CartesianChart/ViewModel/Model.cs b/maui/samples/Gallery/Samples/CartesianChart/ViewModel/Model.cs
index bb0b4973..18407c92 100644
--- a/maui/samples/Gallery/Samples/CartesianChart/ViewModel/Model.cs
+++ b/maui/samples/Gallery/Samples/CartesianChart/ViewModel/Model.cs
@@ -16,6 +16,8 @@ public class ChartDataModel
public double Size { get; set; }
+ public double Volume { get; set; }
+
public double High { get; set; }
public double Low { get; set; }
@@ -57,6 +59,8 @@ public class ChartDataModel
public string? TopMovie { get; set; }
+ public Color? PointColor { get; set; }
+
public ChartDataModel() { }
public ChartDataModel(string department, List employeeAges)
@@ -126,6 +130,16 @@ public ChartDataModel(double name, double high, double low, double open, double
Size = close;
}
+ public ChartDataModel(DateTime date, double high, double low, double open, double close, double volume)
+ {
+ Date = date;
+ Value = open;
+ High = high;
+ Low = low;
+ Size = close;
+ Volume = volume;
+ }
+
public ChartDataModel(DateTime date, double high, double low, double open, double close)
{
Date = date;
diff --git a/maui/samples/Gallery/Samples/DatePicker/Customization/View/Customization.xaml b/maui/samples/Gallery/Samples/DatePicker/Customization/View/Customization.xaml
index c811aa5c..e910d92d 100644
--- a/maui/samples/Gallery/Samples/DatePicker/Customization/View/Customization.xaml
+++ b/maui/samples/Gallery/Samples/DatePicker/Customization/View/Customization.xaml
@@ -94,7 +94,7 @@
-
+
@@ -122,7 +122,7 @@
-
+
diff --git a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml
index a7855bd7..9f7c978a 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml
+++ b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml
@@ -1,63 +1,76 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ShowDataLabels="True"
+ PaletteBrushes="{AppThemeBinding Default={StaticResource PaletteBrushesLight1}, Dark={StaticResource PaletteBrushesDark1}}"
+ StrokeWidth="2" Stroke="{AppThemeBinding Default={StaticResource ContentBackground}}"
+ ItemsSource="{Binding FunnelData}"
+ EnableTooltip="True"
+ TooltipTemplate="{StaticResource tooltipTemplate}"
+ XBindingPath="Name"
+ YBindingPath="Value">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml.cs b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml.cs
index 77c0351d..8d560336 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml.cs
+++ b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/DefaultFunnel.xaml.cs
@@ -12,5 +12,16 @@ public override void OnDisappearing()
base.OnDisappearing();
Chart.Handler?.DisconnectHandler();
}
+
+ private void Inversed_CheckedChanged(object? sender, Microsoft.Maui.Controls.CheckedChangedEventArgs e)
+ {
+ if (sender is Microsoft.Maui.Controls.CheckBox checkBox)
+ {
+ bool isChecked = e.Value;
+ Chart.Orientation = isChecked
+ ? Syncfusion.Maui.Toolkit.Charts.ChartOrientation.Horizontal
+ : Syncfusion.Maui.Toolkit.Charts.ChartOrientation.Vertical;
+ }
+ }
}
}
diff --git a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/Legend.xaml b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/Legend.xaml
index 7d492d02..bcad94ab 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/Legend.xaml
+++ b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartDemo/Legend.xaml
@@ -6,18 +6,19 @@
xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit"
xmlns:converter="clr-namespace:Syncfusion.Maui.ControlsGallery.Converters;assembly=Syncfusion.Maui.ControlsGallery">
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartResource/FunnelChartColorResources.xaml b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartResource/FunnelChartColorResources.xaml
index a14e2896..11abda88 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/FunnelChartResource/FunnelChartColorResources.xaml
+++ b/maui/samples/Gallery/Samples/FunnelChart/FunnelChartResource/FunnelChartColorResources.xaml
@@ -4,54 +4,54 @@
xmlns:local="clr-namespace: Syncfusion.Maui.ControlsGallery.FunnelChart.SfFunnelChart"
x:Class=" Syncfusion.Maui.ControlsGallery.FunnelChart.SfFunnelChart.FunnelChartColorResources">
-
- #DE7207
- #4A9608
- #8E4AFC
- #1D5B6F
- #3068F7
-
+
+ #DE7207
+ #4A9608
+ #8E4AFC
+ #1D5B6F
+ #3068F7
+
-
- #EA4701
- #10AD4F
- #9730E7
- #0DAA97
- #2989F9
-
+
+ #EA4701
+ #10AD4F
+ #9730E7
+ #0DAA97
+ #2989F9
+
-
- #1D5B6F
- #8E4AFC
- #4A9608
- #DE7207
- #3068F7
-
+
+ #1D5B6F
+ #8E4AFC
+ #4A9608
+ #DE7207
+ #3068F7
+
-
- #0DAA97
- #9730E7
- #10AD4F
- #EA4701
- #2989F9
-
+
+ #0DAA97
+ #9730E7
+ #10AD4F
+ #EA4701
+ #2989F9
+
-
- #DE7207
- #ACACAC
- #4A9608
- #8E4AFC
- #1D5B6F
- #3068F7
-
+
+ #DE7207
+ #ACACAC
+ #4A9608
+ #8E4AFC
+ #1D5B6F
+ #3068F7
+
-
- #EA4701
- #666666
- #10AD4F
- #9730E7
- #0DAA97
- #2989F9
-
+
+ #EA4701
+ #666666
+ #10AD4F
+ #9730E7
+ #0DAA97
+ #2989F9
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/FunnelChart/Interaction/Tooltip.xaml b/maui/samples/Gallery/Samples/FunnelChart/Interaction/Tooltip.xaml
index c48dd970..6171d51f 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/Interaction/Tooltip.xaml
+++ b/maui/samples/Gallery/Samples/FunnelChart/Interaction/Tooltip.xaml
@@ -5,46 +5,47 @@
xmlns:localCore="clr-namespace:Syncfusion.Maui.ControlsGallery;assembly=Syncfusion.Maui.ControlsGallery"
xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit">
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/BaseViewModel.cs b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/BaseViewModel.cs
index 7b03853b..029fb033 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/BaseViewModel.cs
+++ b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/BaseViewModel.cs
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.Globalization;
namespace Syncfusion.Maui.ControlsGallery.FunnelChart.SfFunnelChart
{
@@ -77,4 +78,30 @@ public partial class ChartColorModel : ObservableCollection
{
}
+
+ public class TooltipValueConverter : IValueConverter
+ {
+ public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+
+ if (value is ChartDataModel model)
+ {
+ switch (parameter?.ToString())
+ {
+ case "Name":
+ return model.Name;
+ case "Value":
+ return model.Value;
+ case "Percentage":
+ return model.Percentage;
+ }
+ }
+ return value;
+ }
+
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ return value;
+ }
+ }
}
diff --git a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/Model.cs b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/Model.cs
index 3095c8eb..c48589a7 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/Model.cs
+++ b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/Model.cs
@@ -2,7 +2,7 @@
{
public class ChartDataModel
{
- public string? Name { get; set; }
+ public string? Name { get; set; }
public double Data { get; set; }
diff --git a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/ViewModel.cs b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/ViewModel.cs
index 7a22b164..704b6450 100644
--- a/maui/samples/Gallery/Samples/FunnelChart/ViewModel/ViewModel.cs
+++ b/maui/samples/Gallery/Samples/FunnelChart/ViewModel/ViewModel.cs
@@ -4,6 +4,7 @@ namespace Syncfusion.Maui.ControlsGallery.FunnelChart.SfFunnelChart
{
public partial class ViewModel : BaseViewModel
{
+ public string[] OrientationType => new[] { "Vertical", "Horizontal" };
public ObservableCollection FunnelData { get; set; }
public ObservableCollection? RecruitmentData { get; set; }
public ObservableCollection? CustomerData { get; set; }
@@ -12,33 +13,32 @@ public ViewModel()
{
FunnelData =
[
- new ChartDataModel("Renewed", 18),
- new ChartDataModel("Subscribed", 34),
- new ChartDataModel("Contacted Support", 52),
- new ChartDataModel("Downloaded a Trial", 68),
- new ChartDataModel("Visited the Website", 100),
- ];
+ new ChartDataModel("Renewed", 18),
+ new ChartDataModel("Subscribed", 34),
+ new ChartDataModel("Contacted Support", 52),
+ new ChartDataModel("Downloaded a Trial", 68),
+ new ChartDataModel("Visited the Website", 100),
+ ];
RecruitmentData =
[
- new ChartDataModel("Candidates Recruited", 150,30),
- new ChartDataModel("HR Interview",220,44),
- new ChartDataModel("Technical Interview", 341,68.2),
- new ChartDataModel("Aptitude Test", 446,89.2),
- new ChartDataModel("Candidates Applied", 500,100),
- ];
+ new ChartDataModel("Candidates Recruited", 150,30),
+ new ChartDataModel("HR Interview",220,44),
+ new ChartDataModel("Technical Interview", 341,68.2),
+ new ChartDataModel("Aptitude Test", 446,89.2),
+ new ChartDataModel("Candidates Applied", 500,100),
+ ];
CustomerData =
[
- new ChartDataModel("Closed Deals", 80,"80% of 100"),
- new ChartDataModel("Negotiations", 100,"67% of 150"),
- new ChartDataModel("Proposal",150,"75% of 200"),
- new ChartDataModel("Needs Analysis", 200,"50% of 400"),
- new ChartDataModel("Qualified Leads", 400,"80% of 500"),
- new ChartDataModel("Lead Generation", 500,"100%"),
- ];
-
+ new ChartDataModel("Closed Deals", 80,"80% of 100"),
+ new ChartDataModel("Negotiations", 100,"67% of 150"),
+ new ChartDataModel("Proposal",150,"75% of 200"),
+ new ChartDataModel("Needs Analysis", 200,"50% of 400"),
+ new ChartDataModel("Qualified Leads", 400,"80% of 500"),
+ new ChartDataModel("Lead Generation", 500,"100%"),
+ ];
}
}
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml
new file mode 100644
index 00000000..c184f8d7
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml.cs b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml.cs
new file mode 100644
index 00000000..7b10dc57
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStarted.xaml.cs
@@ -0,0 +1,21 @@
+namespace Syncfusion.Maui.ControlsGallery.GridSplitter.SfGridSplitter;
+
+public partial class GettingStarted : SampleView
+{
+#if ANDROID || IOS
+ GettingStartedMobile gettingStartedMobile;
+#elif WINDOWS || MACCATALYST
+ GettingStartedDesktop gettingStartedDesktop;
+#endif
+ public GettingStarted()
+ {
+ InitializeComponent();
+#if ANDROID || IOS
+ gettingStartedMobile = new GettingStartedMobile();
+ this.Content = gettingStartedMobile.Content;
+#elif WINDOWS || MACCATALYST
+ gettingStartedDesktop = new GettingStartedDesktop();
+ this.Content = gettingStartedDesktop.Content;
+#endif
+ }
+}
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml
new file mode 100644
index 00000000..1e7bc285
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml
@@ -0,0 +1,659 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml.cs b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml.cs
new file mode 100644
index 00000000..72ca8d49
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedDesktop.xaml.cs
@@ -0,0 +1,9 @@
+namespace Syncfusion.Maui.ControlsGallery.GridSplitter.SfGridSplitter;
+
+public partial class GettingStartedDesktop : SampleView
+{
+ public GettingStartedDesktop()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml
new file mode 100644
index 00000000..92779d60
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml.cs b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml.cs
new file mode 100644
index 00000000..20bc75c8
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/GettingStarted/View/GettingStartedMobile.xaml.cs
@@ -0,0 +1,9 @@
+namespace Syncfusion.Maui.ControlsGallery.GridSplitter.SfGridSplitter;
+
+public partial class GettingStartedMobile : SampleView
+{
+ public GettingStartedMobile()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/maui/samples/Gallery/Samples/GridSplitter/Helper/GridSplitterBhevaiour.cs b/maui/samples/Gallery/Samples/GridSplitter/Helper/GridSplitterBhevaiour.cs
new file mode 100644
index 00000000..f31cd8e7
--- /dev/null
+++ b/maui/samples/Gallery/Samples/GridSplitter/Helper/GridSplitterBhevaiour.cs
@@ -0,0 +1,281 @@
+using Syncfusion.Maui.Toolkit.GridSplitter;
+
+namespace Syncfusion.Maui.ControlsGallery.GridSplitter;
+
+public class GridSplitterBehaviour : Behavior
+{
+ DashboardViewModel? _viewModel;
+
+ // Desktop named elements
+ Entry? _searchBar;
+ Microsoft.Maui.Controls.Picker? _regionPicker;
+ Microsoft.Maui.Controls.Picker? _statusPicker;
+ Microsoft.Maui.Controls.Picker? _typePicker;
+ Button? _addCustomerButton;
+ Button? _viewAllButton;
+ Label? _closeDetailsIcon;
+ CollectionView? _customersCollectionView;
+
+ // Mobile named elements
+ CollectionView? _photosCollectionView;
+
+ // GridSplitter control
+ Syncfusion.Maui.Toolkit.GridSplitter.SfGridSplitter? _gridSplitter;
+
+ protected override void OnAttachedTo(SampleView bindable)
+ {
+ base.OnAttachedTo(bindable);
+
+ // Reuse the XAML-set BindingContext when it is already a DashboardViewModel so that
+ // inner blocks (which the XAML keeps for compiled-binding support)
+ // all resolve to the same VM instance and stay in sync.
+ if (bindable.BindingContext is DashboardViewModel existing)
+ {
+ _viewModel = existing;
+ }
+ else
+ {
+ _viewModel = new DashboardViewModel();
+ bindable.BindingContext = _viewModel;
+ }
+
+ // Desktop wiring (named elements may not exist on the mobile view)
+ _searchBar = bindable.FindByName("SearchBar");
+ _regionPicker = bindable.FindByName("RegionPicker");
+ _statusPicker = bindable.FindByName("StatusPicker");
+ _typePicker = bindable.FindByName("TypePicker");
+ _addCustomerButton = bindable.FindByName