Skip to content

Commit af8e472

Browse files
committed
Reverted the master changes
1 parent 7aea41a commit af8e472

File tree

1 file changed

+1
-272
lines changed

1 file changed

+1
-272
lines changed

README.md

Lines changed: 1 addition & 272 deletions
Original file line numberDiff line numberDiff line change
@@ -1,272 +1 @@
1-
# How to add multiple trackballs in a WPF SfChart.
2-
This article provides a detailed walkthrough on how to add multiple trackballs in an [SfChart](https://help.syncfusion.com/wpf/charts/getting-started) in WPF, allowing you to hover over the trackball with your mouse and move them independently to view the information of different data points simultaneously.
3-
4-
Learn step-by-step instructions and gain insights to add multiple trackballs in a WPF SfChart.
5-
6-
**Step 1:** Create a custom ChartTrackBallBehaviorExt class, which is inherited from [ChartTrackballBehavior](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.ChartTrackBallBehavior.html#).
7-
8-
C#
9-
10-
```csharp
11-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
12-
{
13-
14-
}
15-
```
16-
17-
**Step 2:** In the constructor of your MainWindow class, initialize the trackballs by setting their SfChart property to the chart defined in your XAML. This ensures that the trackballs are associated with the correct chart instance and can be accessed in other classes.
18-
19-
C#
20-
21-
```csharp
22-
public partial class MainWindow : Window
23-
{
24-
public MainWindow()
25-
{
26-
InitializeComponent();
27-
trackball1.SfChart = this.chart;
28-
trackball2.SfChart = this.chart;
29-
}
30-
}
31-
32-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
33-
{
34-
. . .
35-
public SfChart SfChart { get; set; }
36-
. . .
37-
}
38-
```
39-
40-
**Step 3:** Create instances of ChartTrackBallBehaviorExt, and add them to the [Behaviors](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.SfChart.html#Syncfusion_UI_Xaml_Charts_SfChart_Behaviors) collection, assigning specific names to each.
41-
42-
XAML
43-
44-
```XML
45-
<chart:SfChart.Behaviors>
46-
<local:ChartTrackBallBehaviorExt x:Name="trackball1"/>
47-
<local:ChartTrackBallBehaviorExt x:Name="trackball2"/>
48-
</chart:SfChart.Behaviors>
49-
```
50-
51-
**Step 4:** Override the **OnContentRendered** method to run the asynchronous task that calls ShowTrackball().
52-
53-
C#
54-
55-
```csharp
56-
public partial class MainWindow : Window
57-
{
58-
. . .
59-
protected override void OnContentRendered(EventArgs e)
60-
{
61-
base.OnContentRendered(e);
62-
63-
// Run the ShowTrackball method asynchronously
64-
Task.Run(async () =>
65-
{
66-
await ShowTrackball();
67-
});
68-
}
69-
. . .
70-
}
71-
```
72-
73-
**Step 5:** Implement the **ShowTrackball** method to calculate positions and display the trackballs at load time by using the Display method.
74-
75-
C#
76-
77-
```csharp
78-
public partial class MainWindow : Window
79-
{
80-
. . .
81-
async Task ShowTrackball()
82-
{
83-
// Wait for 1 second before executing the rest of the method
84-
await Task.Delay(1000);
85-
Application.Current.Dispatcher.Invoke(() =>
86-
{
87-
// Calculated positions for the first trackball
88-
float xPosition = (float)chart.ValueToPoint(chart.PrimaryAxis, 1);
89-
float yPosition = (float)chart.ValueToPoint(chart.SecondaryAxis, 169);
90-
91-
// Calculated positions for the second trackball
92-
float xPosition1 = (float)chart.ValueToPoint(chart.PrimaryAxis, 6);
93-
float yPosition1 = (float)chart.ValueToPoint(chart.SecondaryAxis, 170);
94-
95-
// Display the first trackball
96-
trackball1.Display(xPosition, yPosition);
97-
98-
// Display the second trackball
99-
trackball2.Display(xPosition1, yPosition1);
100-
});
101-
}
102-
. . .
103-
}
104-
```
105-
106-
**Step 6:** Implement the **Display** method, which is responsible for displaying the trackball at specified coordinates . It updates the trackball’s position, sets the IsActivated protected property of the ChartTrackBallBehavior class to true, and triggers the necessary internal methods to reflect these changes on the UI.
107-
108-
C#
109-
110-
```csharp
111-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
112-
{
113-
. . .
114-
public void Display(float x, float y)
115-
{
116-
X = x; Y = y;
117-
IsActivated = true;
118-
var point = new Point(x, y);
119-
120-
// Set the internal property for the current point
121-
SetInternalProperty(typeof(ChartTrackBallBehavior), this, point, "CurrentPoint");
122-
123-
// Trigger the pointer position changed event
124-
base.OnPointerPositionChanged();
125-
126-
// Activate the trackball
127-
InvokeInternalMethod(typeof(ChartTrackBallBehavior), this, "Activate", IsActivated);
128-
}
129-
. . .
130-
}
131-
```
132-
133-
**Step 7:** The **SetInternalProperty** method uses reflection to set an internal property of an object. This is useful for accessing and modifying properties that are not publicly accessible.
134-
135-
C#
136-
137-
```csharp
138-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
139-
{
140-
. . .
141-
internal static void SetInternalProperty(Type type, object obj, object value, string propertyName)
142-
{
143-
var properties = type.GetRuntimeProperties();
144-
foreach (var item in properties)
145-
{
146-
if (item.Name == propertyName)
147-
{
148-
item.SetValue(obj, value);
149-
break;
150-
}
151-
}
152-
}
153-
. . .
154-
}
155-
```
156-
157-
**Step 8:** The **InvokeInternalMethod** method uses reflection to invoke an internal method of an object. This allows calling methods that are not publicly accessible.
158-
159-
C#
160-
161-
```csharp
162-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
163-
{
164-
. . .
165-
internal static object? InvokeInternalMethod(Type type, object obj, string methodName, params object[] args)
166-
{
167-
var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
168-
return method?.Invoke(obj, args);
169-
}
170-
. . .
171-
}
172-
```
173-
174-
**Step 9:** Interact with multiple trackballs by overriding the **Mouse Event handlers** of [ChartTrackBallBehavior](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.ChartTrackBallBehavior.html) class. The **FindNearestTrackball** method is called in **OnMouseEnter** method to find the nearest trackball to the mouse pointer. The **isTrackballActive** variable is used to track whether a specific trackball is currently active, ensuring that only the relevant trackball responds to mouse events.
175-
176-
C#
177-
178-
```csharp
179-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
180-
{
181-
private bool isTrackballActive = false;
182-
. . .
183-
protected override void OnMouseEnter(MouseEventArgs e)
184-
{
185-
// Get the position of the mouse pointer
186-
var touchPoint = e.GetPosition(null);
187-
188-
// Find the nearest trackball to the mouse pointer
189-
var trackball = FindNearestTrackball(touchPoint);
190-
191-
// Activate the trackball if it is the nearest one
192-
if (trackball == this)
193-
{
194-
isTrackballActive = true;
195-
base.OnMouseEnter(e);
196-
}
197-
}
198-
199-
protected override void OnMouseMove(MouseEventArgs e)
200-
{
201-
// Check if the trackball is activated
202-
if (isTrackballActive)
203-
{
204-
// Get the position of the mouse pointer
205-
var touchPoint = e.GetPosition(null);
206-
207-
// Display the trackball at the current mouse position
208-
Display((float)touchPoint.X, (float)touchPoint.Y);
209-
base.OnMouseMove(e);
210-
}
211-
}
212-
213-
protected override void OnMouseLeave(MouseEventArgs e)
214-
{
215-
// Deactivate the trackball
216-
isTrackballActive = false;
217-
}
218-
. . .
219-
}
220-
```
221-
222-
**Step 10:** The **FindNearestTrackball** method identifies the trackball closest to the user’s touch point, determining which trackball should be activated or moved based on user interaction.
223-
224-
C#
225-
226-
```csharp
227-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
228-
{
229-
. . .
230-
private ChartTrackBallBehavior FindNearestTrackball(Point touchPoint)
231-
{
232-
ChartTrackBallBehavior nearestTrackball = null;
233-
double minDistance = double.MaxValue;
234-
235-
// Iterate through all trackball behaviors to find the nearest one
236-
foreach (var trackballBehaviour in SfChart.Behaviors)
237-
{
238-
if (trackballBehaviour is ChartTrackBallBehaviorExt trackball)
239-
{
240-
// Calculate the distance between the trackball and the touch point
241-
double distance = Math.Sqrt(Math.Pow(trackball.X - touchPoint.X, 2) + Math.Pow(trackball.Y - touchPoint.Y, 2));
242-
243-
// Update the nearest trackball if the current one is closer
244-
if (distance < minDistance)
245-
{
246-
minDistance = distance;
247-
nearestTrackball = trackball;
248-
}
249-
}
250-
}
251-
252-
return nearestTrackball;
253-
}
254-
. . .
255-
}
256-
```
257-
258-
**Step 11:** To control the trackballs, simply hover over them with your mouse. As you move the mouse within the chart area, the trackball will follow the cursor, allowing you to inspect different data points interactively.
259-
260-
**Output:**
261-
262-
![trackballDemo](https://github.com/user-attachments/assets/0a01c337-49a5-479b-b04f-1719eac9a37e)
263-
264-
265-
## Troubleshooting
266-
### Path too long exception
267-
If you are facing a path too long exception when building this example project, close Visual Studio and rename the repository to short and build the project.
268-
269-
For more details, refer to the KB on [How to add multiple trackballs in a WPF SfChart?](https://support.syncfusion.com/agent/kb/17741/edit).
270-
271-
272-
1+
# How to add multiple trackballs in a WPF SfChart.

0 commit comments

Comments
 (0)