Skip to content

Commit a60024b

Browse files
authored
README.md updated
1 parent 6b1ba64 commit a60024b

File tree

1 file changed

+200
-65
lines changed

1 file changed

+200
-65
lines changed

README.md

Lines changed: 200 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,124 +14,259 @@ public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
1414
}
1515
```
1616

17-
**Step 2:** 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.
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.
1818

19-
XAML
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+
```
2039

21-
```XAML
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
2245
<chart:SfChart.Behaviors>
2346
<local:ChartTrackBallBehaviorExt x:Name="trackball1"/>
2447
<local:ChartTrackBallBehaviorExt x:Name="trackball2"/>
2548
</chart:SfChart.Behaviors>
2649
```
2750

28-
**Step 3:** Override the **OnContentRendered** method to run the asynchronous task that calls ShowTrackball().
51+
**Step 4:** Override the **OnContentRendered** method to run the asynchronous task that calls ShowTrackball().
2952

3053
C#
3154

3255
```csharp
33-
protected override void OnContentRendered(EventArgs e)
56+
public partial class MainWindow : Window
3457
{
35-
base.OnContentRendered(e);
36-
37-
Task.Run(async () =>
58+
. . .
59+
protected override void OnContentRendered(EventArgs e)
3860
{
39-
await ShowTrackball();
40-
});
41-
}
61+
base.OnContentRendered(e);
62+
63+
// Run the ShowTrackball method asynchronously
64+
Task.Run(async () =>
65+
{
66+
await ShowTrackball();
67+
});
68+
}
69+
. . .
70+
}
4271
```
4372

44-
**Step 4:** Implement the **ShowTrackball** method to calculate positions and display the trackballs at load time by using the Show method.
73+
**Step 5:** Implement the **ShowTrackball** method to calculate positions and display the trackballs at load time by using the Display method.
4574

4675
C#
47-
76+
4877
```csharp
49-
async Task ShowTrackball()
78+
public partial class MainWindow : Window
5079
{
51-
await Task.Delay(1000);
52-
Application.Current.Dispatcher.Invoke(() =>
80+
. . .
81+
async Task ShowTrackball()
5382
{
54-
float xPosition = (float)chart.ValueToPoint(chart.PrimaryAxis, 1);
55-
float yPosition = (float)chart.ValueToPoint(chart.SecondaryAxis, 169);
56-
57-
float xPosition1 = (float)chart.ValueToPoint(chart.PrimaryAxis, 6);
58-
float yPosition1 = (float)chart.ValueToPoint(chart.SecondaryAxis, 170);
59-
60-
// Show the first trackball
61-
trackball1.Show(xPosition, yPosition);
62-
63-
// Show the second trackball
64-
trackball2.Show(xPosition1, yPosition1);
65-
});
66-
}
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+
}
67104
```
68105

69-
**Step 5:** 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 **isActivated** variable is used to track whether a specific trackball is currently active, ensuring that only the relevant trackball responds to mouse events.
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.
70107

71108
C#
72109

73110
```csharp
74-
protected override void OnMouseEnter(MouseEventArgs e)
111+
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
75112
{
76-
var touchPoint = e.GetPosition(null);
77-
var trackball = FindNearestTrackball(touchPoint);
78-
79-
if (trackball == this)
113+
. . .
114+
public void Display(float x, float y)
80115
{
81-
isActivated = true;
82-
base.OnMouseEnter(e);
83-
}
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+
. . .
84130
}
131+
```
85132

86-
protected override void OnMouseMove(MouseEventArgs e)
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
87139
{
88-
if (isActivated)
140+
. . .
141+
internal static void SetInternalProperty(Type type, object obj, object value, string propertyName)
89142
{
90-
var touchPoint = e.GetPosition(null);
91-
Show((float)touchPoint.X, (float)touchPoint.Y);
92-
base.OnMouseMove(e);
93-
}
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+
. . .
94154
}
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#
95160

96-
protected override void OnMouseLeave(MouseEventArgs e)
161+
```csharp
162+
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
97163
{
98-
isActivated = false;
99-
}
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+
}
100172
```
101173

102-
**Step 6:** 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.
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.
103175

104176
C#
105-
177+
106178
```csharp
107-
private ChartTrackBallBehavior FindNearestTrackball(Point touchPoint)
179+
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
108180
{
109-
ChartTrackBallBehavior nearestTrackball = null;
110-
double minDistance = double.MaxValue;
111-
112-
foreach (var trackballBehavior in sfChart.Behaviors)
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)
113200
{
114-
if (trackballBehavior is ChartTrackBallBehaviorExt trackballExt)
201+
// Check if the trackball is activated
202+
if (isTrackballActive)
115203
{
116-
var distance = Math.Sqrt(Math.Pow(trackballExt.X - touchPoint.X, 2) + Math.Pow(trackballExt.Y - touchPoint.Y, 2));
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+
```
117221

118-
if (distance < minDistance)
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)
119239
{
120-
minDistance = distance;
121-
nearestTrackball = trackballExt;
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+
}
122249
}
123250
}
251+
252+
return nearestTrackball;
124253
}
125-
return nearestTrackball;
126-
}
254+
. . .
255+
}
127256
```
128257

129-
**Step 7:** 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.
130-
131-
KB Article - [Link](https://support.syncfusion.com/agent/kb/17741).
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.
132259

133260
**Output:**
134261

135-
![trackball demo](https://github.com/user-attachments/assets/4aa5c4b7-4fac-4bc7-9d61-efa33899839d)
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+
136271

137272

0 commit comments

Comments
 (0)