Skip to content

Commit 122ed5b

Browse files
committed
Reverted .VS file
1 parent d0466e9 commit 122ed5b

18 files changed

+140
-637
lines changed

README.md

Lines changed: 140 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -3,144 +3,153 @@ This article provides a detailed walkthrough on how to add multiple trackballs i
33

44
Learn step-by-step instructions and gain insights to add multiple trackballs in a WPF SfChart.
55

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#).
6+
**Step 1:** Initialize the SfChart with primary and secondary axes. For more detailed steps, refer to the WPF Charts [documentation](https://help.syncfusion.com/wpf/charts/getting-started).
77

8-
C#
8+
XAML
99

10-
```csharp
11-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
12-
{
10+
```XML
11+
<Grid>
1312

14-
}
15-
```
13+
<chart:SfChart x:Name="chart">
1614

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.
15+
<chart:SfChart.PrimaryAxis>
16+
<chart:CategoryAxis/>
17+
</chart:SfChart.PrimaryAxis>
1818

19-
C#
19+
<chart:SfChart.SecondaryAxis>
20+
<chart:NumericalAxis/>
21+
</chart:SfChart.SecondaryAxis>
2022

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-
}
23+
<chart:LineSeries ItemsSource="{Binding Data}"
24+
XBindingPath="Day"
25+
YBindingPath="CPULoad" >
26+
</chart:LineSeries>
27+
28+
</chart:SfChart>
29+
30+
</Grid>
31+
```
32+
33+
**Step 2:** Create a custom ChartTrackBallBehaviorExt class, which is inherited from [ChartTrackballBehavior](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.ChartTrackBallBehavior.html#).
34+
35+
C#
3136

37+
```csharp
3238
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
3339
{
34-
. . .
35-
public SfChart SfChart { get; set; }
36-
. . .
40+
3741
}
38-
```
42+
```
3943

4044
**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.
4145

4246
XAML
43-
44-
```XML
47+
48+
```XML
4549
<chart:SfChart.Behaviors>
4650
<local:ChartTrackBallBehaviorExt x:Name="trackball1"/>
4751
<local:ChartTrackBallBehaviorExt x:Name="trackball2"/>
4852
</chart:SfChart.Behaviors>
49-
```
53+
```
5054

51-
**Step 4:** Override the **OnContentRendered** method to run the asynchronous task that calls ShowTrackball().
55+
**Step 4:** Implement the **ChartTrackBallBehaviorExt** class and its functionalities. Include the **Display** method, which is responsible for displaying the trackball at specified coordinates by setting the IsActivated protected property of the ChartTrackBallBehavior class. Manage multiple trackballs by overriding **mouse event handlers** in ChartTrackBallBehavior, using the **FindNearestTrackball** method in **OnMouseEnter** to locate the closest trackball. The **isTrackballActive** variable ensures only the active trackball responds to the events.
5256

5357
C#
5458

55-
```csharp
56-
public partial class MainWindow : Window
59+
```csharp
60+
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
5761
{
58-
. . .
59-
protected override void OnContentRendered(EventArgs e)
62+
private bool isTrackballActive = false;
63+
64+
public SfChart? SfChart { get; set; }
65+
66+
public double X { get; set; }
67+
public double Y { get; set; }
68+
69+
protected override void OnMouseEnter(MouseEventArgs e)
6070
{
61-
base.OnContentRendered(e);
62-
63-
// Run the ShowTrackball method asynchronously
64-
Task.Run(async () =>
71+
// Get the position of the mouse pointer
72+
var touchPoint = e.GetPosition(null);
73+
74+
// Find the nearest trackball to the mouse pointer
75+
var trackball = FindNearestTrackball(touchPoint);
76+
77+
// Activate the trackball if it is the nearest one
78+
if (trackball == this)
6579
{
66-
await ShowTrackball();
67-
});
80+
isTrackballActive = true;
81+
base.OnMouseEnter(e);
82+
}
6883
}
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.
7484

75-
C#
76-
77-
```csharp
78-
public partial class MainWindow : Window
79-
{
80-
. . .
81-
async Task ShowTrackball()
85+
protected override void OnMouseMove(MouseEventArgs e)
8286
{
83-
// Wait for 1 second before executing the rest of the method
84-
await Task.Delay(1000);
85-
Application.Current.Dispatcher.Invoke(() =>
87+
// Check if the trackball is activated
88+
if (isTrackballActive)
8689
{
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-
});
90+
// Get the position of the mouse pointer
91+
var touchPoint = e.GetPosition(null);
92+
93+
// Display the trackball at the current mouse position
94+
Display((float)touchPoint.X, (float)touchPoint.Y);
95+
base.OnMouseMove(e);
96+
}
10197
}
102-
. . .
103-
}
104-
```
10598

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.
99+
protected override void OnMouseLeave(MouseEventArgs e)
100+
{
101+
// Deactivate the trackball
102+
isTrackballActive = false;
103+
}
104+
105+
private ChartTrackBallBehavior FindNearestTrackball(Point touchPoint)
106+
{
107+
ChartTrackBallBehavior nearestTrackball = new ChartTrackBallBehaviorExt();
108+
double minDistance = double.MaxValue;
109+
110+
// Iterate through all trackball behaviors to find the nearest one
111+
if (SfChart != null)
112+
{
113+
foreach (var trackballBehaviour in SfChart.Behaviors)
114+
{
115+
if (trackballBehaviour is ChartTrackBallBehaviorExt trackball)
116+
{
117+
// Calculate the distance between the trackball and the touch point
118+
double distance = Math.Sqrt(Math.Pow(trackball.X - touchPoint.X, 2) + Math.Pow(trackball.Y - touchPoint.Y, 2));
119+
120+
// Update the nearest trackball if the current one is closer
121+
if (distance < minDistance)
122+
{
123+
minDistance = distance;
124+
nearestTrackball = trackball;
125+
}
126+
}
127+
}
128+
}
129+
return nearestTrackball;
130+
}
107131

108-
C#
109-
110-
```csharp
111-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
112-
{
113-
. . .
114132
public void Display(float x, float y)
115133
{
116134
X = x; Y = y;
117135
IsActivated = true;
118136
var point = new Point(x, y);
119-
137+
120138
// Set the internal property for the current point
121139
SetInternalProperty(typeof(ChartTrackBallBehavior), this, point, "CurrentPoint");
122-
140+
123141
// Trigger the pointer position changed event
124142
base.OnPointerPositionChanged();
125-
143+
126144
// Activate the trackball
127145
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#
146+
}
136147

137-
```csharp
138-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
139-
{
140-
. . .
148+
// Sets an internal property of an object using reflection.
141149
internal static void SetInternalProperty(Type type, object obj, object value, string propertyName)
142150
{
143151
var properties = type.GetRuntimeProperties();
152+
144153
foreach (var item in properties)
145154
{
146155
if (item.Name == propertyName)
@@ -149,113 +158,67 @@ public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
149158
break;
150159
}
151160
}
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#
161+
}
160162

161-
```csharp
162-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
163-
{
164-
. . .
163+
// Invokes an internal method of an object using reflection.
165164
internal static object? InvokeInternalMethod(Type type, object obj, string methodName, params object[] args)
166165
{
167166
var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
168167
return method?.Invoke(obj, args);
169-
}
170-
. . .
171-
}
172-
```
168+
}
169+
}
170+
```
173171

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.
172+
**Step 5:** 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 accessible in other classes. Override the **OnContentRendered** method to run an asynchronous task that calls ShowTrackball(). Implement the **ShowTrackball** method to calculate positions and display the trackballs at load time using the Display method.
175173

176174
C#
177175

178-
```csharp
179-
public class ChartTrackBallBehaviorExt : ChartTrackBallBehavior
176+
```csharp
177+
public partial class MainWindow : Window
180178
{
181-
private bool isTrackballActive = false;
182-
. . .
183-
protected override void OnMouseEnter(MouseEventArgs e)
179+
public MainWindow()
184180
{
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-
}
181+
InitializeComponent();
182+
trackball1.SfChart = this.chart;
183+
trackball2.SfChart = this.chart;
197184
}
198-
199-
protected override void OnMouseMove(MouseEventArgs e)
185+
186+
protected override void OnContentRendered(EventArgs e)
200187
{
201-
// Check if the trackball is activated
202-
if (isTrackballActive)
188+
base.OnContentRendered(e);
189+
190+
// Run the ShowTrackball method asynchronously
191+
Task.Run(async () =>
203192
{
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-
}
193+
await ShowTrackball();
194+
});
211195
}
212-
213-
protected override void OnMouseLeave(MouseEventArgs e)
196+
197+
async Task ShowTrackball()
214198
{
215-
// Deactivate the trackball
216-
isTrackballActive = false;
217-
}
218-
. . .
219-
}
220-
```
199+
// Wait for 1 second before executing the rest of the method
200+
await Task.Delay(1000);
201+
Application.Current.Dispatcher.Invoke(() =>
202+
{
203+
// Calculated positions for the first trackball
204+
float xPosition = (float)chart.ValueToPoint(chart.PrimaryAxis, 1);
205+
float yPosition = (float)chart.ValueToPoint(chart.SecondaryAxis, 169);
221206

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.
207+
// Calculated positions for the second trackball
208+
float xPosition1 = (float)chart.ValueToPoint(chart.PrimaryAxis, 6);
209+
float yPosition1 = (float)chart.ValueToPoint(chart.SecondaryAxis, 170);
223210

224-
C#
211+
// Display the first trackball
212+
trackball1.Display(xPosition, yPosition);
225213

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;
214+
// Display the second trackball
215+
trackball2.Display(xPosition1, yPosition1);
216+
});
253217
}
254-
. . .
255-
}
256-
```
218+
}
219+
```
257220

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.
221+
**Step 6:** 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.
259222

260223
**Output:**
261224

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-49 KB
Binary file not shown.

0 commit comments

Comments
 (0)