控件 控件支持涉及 cBot、指标和插件的某些交互。 使用以下指南,您可以轻松地在图表上直接创建基本和高级的 UI 控件。
有几个内置类代表流行的控件,如按钮、文本块、文本框和形状。 然而,您也可以创建自定义控件。
考虑以下示例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = "Click Me")]
public string Text { get ; set ; }
[Parameter(DefaultValue = HorizontalAlignment.Center)]
public HorizontalAlignment HorizontalAlignment { get ; set ; }
[Parameter(DefaultValue = VerticalAlignment.Center)]
public VerticalAlignment VerticalAlignment { get ; set ; }
protected override void Initialize ()
{
var button = new Button
{
Text = Text ,
HorizontalAlignment = HorizontalAlignment ,
VerticalAlignment = VerticalAlignment
};
button . Click += Button_Click ;
Chart . AddControl ( button );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
obj . Button . Text = "You clicked me, thanks" ;
}
public override void Calculate ( int index )
{
}
}
}
如果您构建上述指标并创建一个实例,您应该会在图表的正中心看到一个灰色的 点击我 按钮。
控件与图表对象的区别 在前面的部分 中,我们已经介绍了图表对象。 控件使用户能够与 cBot 和指标进行交互。 相反,图表对象提供了在交易图表或分离的指标输出窗口中绘制内容的机会。
图表控件派生自 ControlBase 类,而图表对象则派生自 ChartObject 类。
图表控件通过使用不同的对齐选项静态定位。 虽然图表对象可以以完全相同的方式定位,但它们的位置也可以根据某些 X 和 Y 坐标动态变化。
与图表对象类似,图表控件可以添加到主图表和任何指标输出窗口(如果存在)。 下面给出了这种定位的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = "Click Me")]
public string Text { get ; set ; }
[Parameter(DefaultValue = HorizontalAlignment.Center)]
public HorizontalAlignment HorizontalAlignment { get ; set ; }
[Parameter(DefaultValue = VerticalAlignment.Center)]
public VerticalAlignment VerticalAlignment { get ; set ; }
protected override void Initialize ()
{
var button = new Button
{
Text = Text ,
HorizontalAlignment = HorizontalAlignment ,
VerticalAlignment = VerticalAlignment
};
button . Click += Button_Click ;
IndicatorArea . AddControl ( button );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
obj . Button . Text = "You clicked me, thanks" ;
}
public override void Calculate ( int index )
{
}
}
}
创建指标实例后,您应该在指标输出窗口中看到一个 点击我 按钮。
ColorPicker ColorPicker 控件使交易者能够为 cTrader 中的关键元素或对象选择他们喜欢的颜色。 例如,开发者可以将 ColorPicker 控件集成到绘制趋势线的 cBot 中,以便用户可以为每条趋势线选择他们喜欢的颜色。 这种设置使交易者更容易区分不同类型的趋势线。
向图表添加指标的插件也可以实现 ColorPicker 控件,因为此功能允许用户为不同的指标线选择颜色。
当用户点击颜色方块时,颜色选择器会出现。 用户随后可以在标准颜色和自定义颜色之间进行选择。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 using System ;
using cAlgo.API ;
using cAlgo.API.Collections ;
using cAlgo.API.Indicators ;
using cAlgo.API.Internals ;
namespace cAlgo.Plugins
{
[Plugin(AccessRights = AccessRights.None)]
public class ColorPickerTest : Plugin
{
protected override void OnStart ()
{
var aspBlock = Asp . SymbolTab . AddBlock ( "Color Picker" );
var colorPicker = new ColorPicker { IsStretched = true , SelectedColor = Color . Red , Height = 20 , Width = 20 , HorizontalAlignment = HorizontalAlignment . Center , VerticalAlignment = VerticalAlignment . Center };
aspBlock . Child = colorPicker ;
colorPicker . SelectedColorChanged += colorPicker_SelectedColorChanged ;
}
private void colorPicker_SelectedColorChanged ( ColorPickerSelectedColorChangedEventArgs obj )
{
Print ( $"colorPicker_SelectedColorChanged, NewSelectedColor: {obj.NewSelectedColor} | PreviousSelectedColor: {obj.PreviousSelectedColor}" );
}
protected override void OnStop ()
{
// Handle Plugin stop here
}
}
}
DropZone DropZone 控件使交易者能够执行涉及 cBot、指标或插件的拖放操作。 要在您的算法中实现此控件,请使用 DropZone 类。 DropZone 控件可以像任何其他控件一样进行操作。
当用户将兼容的文件或文件夹拖放到框中时,会生成 Dropped 事件。 当用户将文件夹或多个文件夹拖放到框中时,只有 FilterExtensions 中指定扩展名的兼容文件会被处理和复制。
注意
拖放的文件通常会被复制并保存在以下位置: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\
cBot 实例的位置与上述不同: ..\Documents\cAlgo\Data\cBots\{cBotName}\{unique-instance-number}\Selected files\
此插件代码向您展示了如何将 DropZone 控件添加到交易观察 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 using System ;
using System.Drawing ;
using cAlgo.API ;
using cAlgo.API.Collections ;
using cAlgo.API.Indicators ;
using cAlgo.API.Internals ;
namespace cAlgo.Plugins
{
[Plugin(AccessRights = AccessRights.None)]
public class TradeWatchTabSample : Plugin
{
protected override void OnStart ()
{
var tab = TradeWatch . AddTab ( "DropZone" );
var _border = new Border
{
BorderThickness = 3 ,
BorderColor = Color . DarkGray ,
Opacity = 0.7 ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
Height = 200 ,
Width = 350 ,
BackgroundColor = Color . LightGray
};
var _textBlock = new TextBlock
{
Text = "Drag your files here" ,
Opacity = 1 ,
ForegroundColor = Color . DarkGray ,
FontSize = 16 ,
VerticalAlignment = VerticalAlignment . Center ,
HorizontalAlignment = HorizontalAlignment . Center
};
var _dropzone = new DropZone
{
FilterExtensions = new string [] { "txt" , "algo" , "csv" },
IsDirectoryDropAllowed = true ,
IsVisible = true ,
IsEnabled = true
};
_border . Child = _textBlock ;
_dropzone . Child = _border ;
// _dropzone.Child = _textBlock;
tab . Child = _dropzone ;
_dropzone . Dropped += Dropped_file ;
}
private void Dropped_file ( DroppedEventArgs obj )
{
Print ( "File has been added!" );
}
}
}
ProgressBar ProgressBar 控件显示正在进行的操作的进度。 进度条使算法更加用户友好,并帮助管理交易者对某些操作等待时间的期望。
cTrader Algo API 允许开发者添加两种类型的 ProgressBar 控件:无限控制和确定控制。
无限控制 您可能希望在以下情况下使用无限控制:
您无法确定操作的等待时间。 您无法检测操作的进度。 您不想指示操作将花费多长时间。
确定控制 当您可以确定操作的等待时间并希望用户看到基于该时间的指示器时,您可能希望使用此控件。
要显示操作的进度,请使用 Value 属性设置一个数值。 要设置进度条百分比,请使用 Minimum 和 Maximum 属性。
下面的插件代码向您展示了如何使用无限和确定(绿色)控件创建进度条:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 using System ;
using cAlgo.API ;
using cAlgo.API.Collections ;
using cAlgo.API.Indicators ;
using cAlgo.API.Internals ;
namespace cAlgo.Plugins
{
[Plugin(AccessRights = AccessRights.None)]
public class ProgressBarTest : Plugin
{
private ProgressBar _infiniteProgressBar ;
private ProgressBar _determinateProgressBar ;
protected override void OnStart ()
{
var aspBlock = Asp . SymbolTab . AddBlock ( "Progress bar" );
var panel = new StackPanel () { Height = 200 , Width = 200 , Orientation = Orientation . Vertical };
_infiniteProgressBar = new ProgressBar { IsIndeterminate = true , Height = 20 };
panel . AddChild ( _infiniteProgressBar );
_determinateProgressBar = new ProgressBar { IsIndeterminate = false , Height = 20 };
panel . AddChild ( _determinateProgressBar );
var autoProgressButton = new Button { Text = "Start" };
autoProgressButton . Click += AutoProgressButton_Click ;
panel . AddChild ( autoProgressButton );
aspBlock . Child = panel ;
}
private void AutoProgressButton_Click ( ButtonClickEventArgs obj )
{
Timer . Start ( 1 );
}
protected override void OnTimer ()
{
_determinateProgressBar . Value ++ ;
Print ( $"Value: {_determinateProgressBar.Value}" );
}
protected override void OnStop ()
{
// Handle Plugin stop here
}
}
}
对话框 OpenFileDialog 和 OpenFolderDialog cTrader Algo API 提供了 OpenFileDialog 接口,使用户能够为算法选择文件。 当用户在生成的窗口中选择文件时,文件会被复制到算法的 Selected files 文件夹中。 算法可以无限制地处理其 Selected files 文件夹中的文件。
提示
当您需要加载重要数据文件、备份或配置文件、自定义指标或脚本时,请使用 OpenFileDialog 功能。
下面的代码向您展示了如何在指标中使用 OpenFileDialog 对话框:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 using System ;
using cAlgo.API ;
using System.Text ;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
public class OpenFileDialogExample : Indicator
{
private OpenFileDialog _openFileDialog ;
protected override void Initialize ()
{
_openFileDialog = new OpenFileDialog ()
{
InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . MyDocuments ),
Multiselect = true ,
Title = "My Open File Dialog Title"
};
var showOpenFileDialog = new Button { Text = "Show Open File Dialog" };
showOpenFileDialog . Click += showOpenFileDialog_Click ;
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( showOpenFileDialog );
Chart . AddControl ( panel );
}
private void showOpenFileDialog_Click ( ButtonClickEventArgs obj )
{
var result = _openFileDialog . ShowDialog ();
Print ( $"Result: {result} | FileName: {_openFileDialog.FileName} | FileNames: {string.Join(',', _openFileDialog.FileNames)}" );
}
public override void Calculate ( int index )
{
}
}
}
cTrader Algo API 提供了 OpenFolderDialog 接口,允许用户为算法指定一个文件夹。 当用户在结果窗口中选择一个文件夹时,所选文件夹内的所有文件和文件夹都会被复制到算法的 Selected files 文件夹中。
提示
当您需要加载包含关键数据文件、备份或配置文件、自定义指标或脚本的文件夹时,请使用 OpenFolderDialog 功能。
所选文件和文件夹通常会被复制到 Selected files 文件夹中,因为即使其 AccessRights 设置为 None,算法也可以处理该文件夹中的项目。
注意
算法的 Selected files 文件夹通常位于以下路径:..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\
cBot 实例的 Selected files 文件夹与上述路径不同:..\Documents\cAlgo\Data\cBots\{cBotName}\{Instance-Id}\Selected files\
下面的代码向您展示了如何在指标中使用 OpenFolderDialog 对话框:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 using System ;
using cAlgo.API ;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
public class OpenFolderDialogExample : Indicator
{
private OpenFolderDialog _openFolderDialog ;
protected override void Initialize ()
{
_openFolderDialog = new OpenFolderDialog ()
{
InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . MyDocuments ),
Title = "My Open Folder Dialog Title"
};
var showOpenFolderDialog = new Button { Text = "Show Open Folder Dialog" };
showOpenFolderDialog . Click += showOpenFolderDialog_Click ;
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( showOpenFolderDialog );
Chart . AddControl ( panel );
}
private void showOpenFolderDialog_Click ( ButtonClickEventArgs obj )
{
var result = _openFolderDialog . ShowDialog ();
Print ( $"Result: {result} | FolderName: {_openFolderDialog.FolderName}" );
}
public override void Calculate ( int index )
{
}
}
}
SaveFileDialog cTrader Algo API 提供了 SaveFileDialog 接口,允许用户将文件(本地)保存到他们的计算机中。 当相关窗口出现时,用户选择要保存文件的文件夹并输入文件名。 文件随后会被保存到指定位置。
提示
当您需要执行以下操作时,请使用 SaveFileDialog 功能:
保存性能报告、回测结果、配置文件或优化数据。 导出交易日志、操作记录或一般用户活动数据。 存储自定义指标、图表和可视化数据或策略参数。 下面的代码向您展示了如何在指标中使用 SaveFileDialog 对话框:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 using System ;
using cAlgo.API ;
using System.Text ;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
public class SaveFileDialogExample : Indicator
{
private SaveFileDialog _saveFileDialog ;
protected override void Initialize ()
{
_saveFileDialog = new SaveFileDialog ()
{
InitialDirectory = Environment . GetFolderPath ( Environment . SpecialFolder . MyDocuments ),
Title = "My Save File Dialog Title"
};
var showSaveFileDialogText = new Button { Text = "Show Save File Dialog (Set Content as text)" };
var showSaveFileDialogBytes = new Button { Text = "Show Save File Dialog (Set Content as bytes)" };
showSaveFileDialogText . Click += showSaveFileDialogText_Click ;
showSaveFileDialogBytes . Click += showSaveFileDialogBytes_Click ;
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( showSaveFileDialogText );
panel . AddChild ( showSaveFileDialogBytes );
Chart . AddControl ( panel );
}
private void showSaveFileDialogText_Click ( ButtonClickEventArgs obj )
{
var result = _saveFileDialog . ShowDialog ();
Print ( $"Result: {result}" );
if ( result != FileDialogResult . Cancel )
{
_saveFileDialog . WriteToFile ( "Test in text" );
}
}
private void showSaveFileDialogBytes_Click ( ButtonClickEventArgs obj )
{
var result = _saveFileDialog . ShowDialog ();
Print ( $"Result: {result}" );
if ( result != FileDialogResult . Cancel )
{
_saveFileDialog . WriteToFile ( Encoding . UTF8 . GetBytes ( "Test in bytes" ));
}
}
public override void Calculate ( int index )
{
}
}
}
可拖动控件 图表区域可拖动控件 ChartDraggable 和 ChartDraggables 接口提供了类型,允许您向图表添加一个可拖动控件,该控件能够承载其他控件和不同元素。 这些可拖动控件使用户更容易与各种图表元素进行交互。
注意
可拖动控件只能在添加它的图表内移动或重新定位。
以下代码展示了如何创建一个指标,该指标添加了两个可以在图表内移动的控件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 using System ;
using cAlgo.API ;
using cAlgo.API.Collections ;
using cAlgo.API.Indicators ;
using cAlgo.API.Internals ;
namespace cAlgo
{
[Indicator(AccessRights = AccessRights.None)]
public class DragControl : Indicator
{
protected override void Initialize ()
{
var draggable = Chart . Draggables . Add ();
var draggable2 = IndicatorArea . Draggables . Add ();
draggable . Child = GetDraggableChildWebView ();
draggable2 . Child = GetDraggableChildText ();
draggable . LocationChanged += draggable_LocationChanged ;
draggable2 . LocationChanged += draggable2_LocationChanged ;
}
public override void Calculate ( int index )
{
// Calculate value at specified index
// Result[index] =
}
private StackPanel GetDraggableChildWebView ()
{
var stackPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
BackgroundColor = Color . Gold
};
var webView = new WebView () { Height = 500 , Width = 300 };
webView . Loaded += webView_Loaded ;
stackPanel . AddChild ( webView );
return stackPanel ;
}
private StackPanel GetDraggableChildText ()
{
var stackPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
BackgroundColor = Color . Gold
};
var text_block = new TextBlock
{
Text = "Testing draggable controls" ,
Margin = 5 ,
ForegroundColor = Color . Black ,
FontWeight = FontWeight . ExtraBold
};
stackPanel . AddChild ( text_block );
return stackPanel ;
}
private void webView_Loaded ( WebViewLoadedEventArgs obj )
{
obj . WebView . NavigateAsync ( "https://www.youtube.com/" );
}
private void draggable_LocationChanged ( ChartDraggableLocationChangedEventArgs obj )
{
Print ( $"Draggable '{obj.Draggable.Id}' location changed to: ({obj.Draggable.X}, {obj.Draggable.Y})" );
}
private void draggable2_LocationChanged ( ChartDraggableLocationChangedEventArgs obj )
{
Print ( $"Draggable '{obj.Draggable.Id}' location changed to: ({obj.Draggable.X}, {obj.Draggable.Y})" );
}
}
}
应用程序窗口可拖动控件 ApplicationDraggable 和 ApplicationDraggables 接口提供了用于添加浮动控件的类型,这些控件可以在整个 cTrader 应用程序窗口内单独移动。 此类控件使您能够创建交互式和动态的用户界面。
注意
在三种算法类型中,只有插件允许实现应用程序范围内的可拖动控件。
以下代码展示了如何创建一个插件,该插件添加了一个 WebView 组件和文本块,分别位于两个独立的窗口中,可以在整个 cTrader UI 中移动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 using System ;
using cAlgo.API ;
using cAlgo.API.Internals ;
namespace cAlgo.Plugins
{
[Plugin(AccessRights = AccessRights.None)]
public class ApplicationLevelDraggables : Plugin
{
private ApplicationDraggable _webDraggable ;
private ApplicationDraggable _textDraggable ;
protected override void OnStart ()
{
_webDraggable = Application . Draggables . Add ();
_webDraggable . Child = GetDraggableChildWebView ();
_webDraggable . LocationChanged += OnDraggableLocationChanged ;
_textDraggable = Application . Draggables . Add ();
_textDraggable . Child = GetDraggableChildText ();
_textDraggable . LocationChanged += OnDraggableLocationChanged ;
}
private void OnDraggableLocationChanged ( ApplicationDraggableLocationChangedEventArgs args )
{
Print ( $"Draggable '{args.Draggable.Id}' location changed to: ({args.Draggable.X}, {args.Draggable.Y})" );
}
private StackPanel GetDraggableChildWebView ()
{
var stackPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
BackgroundColor = Color . Gold
};
var webView = new WebView { Width = 300 , Height = 200 };
webView . Loaded += ( args ) => args . WebView . NavigateAsync ( "https://www.youtube.com/" );
stackPanel . AddChild ( webView );
return stackPanel ;
}
private StackPanel GetDraggableChildText ()
{
var stackPanel = new StackPanel
{
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
BackgroundColor = Color . Gold
};
var textBlock = new TextBlock
{
Text = "Testing Application-level draggable" ,
Margin = 5 ,
ForegroundColor = Color . Black ,
FontWeight = FontWeight . ExtraBold
};
stackPanel . AddChild ( textBlock );
return stackPanel ;
}
}
}
选项卡控件 TabControl 类提供了类型,允许您为算法创建多个选项卡。 这些选项卡可用于将相关元素保持在一起,或为功能提供单独的视图。
以下代码展示了如何在添加到活跃交易品种面板的插件中使用选项卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 using System ;
using System.Linq ;
using cAlgo.API ;
using cAlgo.API.Internals ;
namespace cAlgo.Plugins
{
[Plugin(AccessRights = AccessRights.FullAccess)]
public class TabControlSimple : Plugin
{
private TabControl _tabControl ;
protected override void OnStart ()
{
_tabControl = new TabControl
{
Height = 200 ,
TabStripPlacement = Dock . Left
};
var firstTab = new TabItem
{
Header = new TextBlock { Text = "First Tab" },
Content = new TextBlock { Text = "First Tab Content" , BackgroundColor = Color . Red }
};
var secondTab = new TabItem
{
Header = new TextBlock { Text = "Second Tab" },
Content = new TextBlock { Text = "Second Tab Content" }
};
_tabControl . AddTab ( firstTab );
_tabControl . AddTab ( secondTab );
_tabControl . SelectedTabChanged += TabControl_SelectedTabChanged ;
_tabControl . SelectedTab = secondTab ;
var panel = new StackPanel { Orientation = Orientation . Vertical };
panel . AddChild ( _tabControl );
var asp = Asp . SymbolTab . AddBlock ( "Simple Tab Control" );
asp . Child = panel ;
asp . Height = 300 ;
}
private void TabControl_SelectedTabChanged ( TabControlSelectedTabChangedEventArgs obj )
{
Print ( $"Selected tab changed to: {obj.SelectedTab?.UniqueId}" );
}
protected override void OnStop ()
{
}
}
}
自定义控件 自定义控件本质上是由多个预定义控件构成的控件。 换句话说,它是一个由其他控件构成其内容的控件。
自定义控件与内置控件类似,可作为可重用类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter("# Of Text Areas", DefaultValue = 4)]
public int NumberOfTextAreas { get ; set ; }
protected override void Initialize ()
{
var panel = new WrapPanel
{
Orientation = Orientation . Horizontal ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
for ( int i = 0 ; i < NumberOfTextAreas ; i ++ )
{
var textArea = new TextArea
{
HorizontalAlignment = HorizontalAlignment . Right ,
VerticalAlignment = VerticalAlignment . Stretch ,
Margin = 5 ,
};
panel . AddChild ( textArea );
}
Chart . AddControl ( panel );
}
public override void Calculate ( int index )
{
}
}
public class TextArea : CustomControl
{
private readonly TextBox _textBox ;
public TextArea ()
{
_textBox = new TextBox
{
TextAlignment = TextAlignment . Left ,
TextWrapping = TextWrapping . Wrap ,
AcceptsReturn = true ,
AcceptsTab = true ,
Width = 300 ,
Height = 200 ,
};
AddChild ( _textBox );
}
}
}
此指标的实例应在主图表的中心直接显示四个文本框。
使用面板组织控件 为了使控件操作更加方便,您可能希望将多个控件放置在一个具有独立位置的组中。 为此,您可以使用 Panels 类及其派生类。
将面板视为一个包含其他控件作为其内容的控件。 cTrader 支持从基础 Panels 类(该类本身继承自 Control 类)继承的五种不同类:
Canvas DockPanel Grid StackPanel WrapPanel 上述每个类使用不同的面板布局和定位策略,如下所述。
画布 画布是一种允许基于特定 X 和 Y 坐标定位控件的面板。
值得注意的是,X 和 Y 轴与图表对象或绘图使用的轴不同。 Canvas 类使用的 X 和 Y 坐标表示从图表左上角 (0, 0) 开始的数值。
考虑以下示例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = "Click Me")]
public string Text { get ; set ; }
[Parameter(DefaultValue = 0)]
public double Left { get ; set ; }
[Parameter(DefaultValue = 0)]
public double Top { get ; set ; }
[Parameter(DefaultValue = 0)]
public double Margin { get ; set ; }
[Parameter(DefaultValue = 10)]
public double Padding { get ; set ; }
protected override void Initialize ()
{
var button = new Button
{
Text = Text ,
Left = Left ,
Top = Top ,
Margin = Margin ,
Padding = Padding
};
button . Click += Button_Click ;
var canvas = new Canvas ();
/* We add our button control to the canvas
panel. */
canvas . AddChild ( button );
// We add our canvas panel to the chart.
Chart . AddControl ( canvas );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
obj . Button . Text = "You clicked me, thanks" ;
}
public override void Calculate ( int index )
{
}
}
}
创建上述指标的实例后,您应该会在图表的左上角看到 Click me 按钮。
控件的 Top 属性决定了它在 Y 轴上的位置。 反过来,Left 属性定义了它在 X 轴上的位置。
上述代码还使用了 Padding 和 Margin 属性。 Padding 指的是控件内容与其外边框之间的距离。 Margin 是控件与其父容器边框之间的距离。 Padding 和 Margin 属性适用于所有面板,而不仅仅是画布类。 它们对于管理控件之间的间距非常有用。
在大多数情况下,Canvas 类仅用于分组少量控件。
停靠面板 DockPanel 类用于将控件停靠(放置)在图表上的静态位置。 有四种可能的停靠位置:
每个控件都有一个 Dock 属性。 使用 DockPanel 类时,您可以使用此属性将控件定位在 DockPanel 内。 以下示例说明了这一点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = Dock.Top)]
public Dock TextBoxDock { get ; set ; }
[Parameter(DefaultValue = Dock.Bottom)]
public Dock ButtonDock { get ; set ; }
private TextBox _textBox ;
protected override void Initialize ()
{
_textBox = new TextBox
{
Margin = 5 ,
Text = "Write here..." ,
ForegroundColor = Color . Yellow ,
Dock = TextBoxDock ,
Width = 200
};
var button = new Button
{
Text = "Tell what I wrote?" ,
Dock = ButtonDock ,
Width = 200
};
button . Click += Button_Click ;
var dockPanel = new DockPanel
{
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
};
dockPanel . AddChild ( _textBox );
dockPanel . AddChild ( button );
Chart . AddControl ( dockPanel );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
obj . Button . Text = $"You wrote: {_textBox.Text}" ;
}
public override void Calculate ( int index )
{
}
}
}
创建此指标的实例时,您应该会在图表的中心看到一个停靠面板,其中包含一个文本字段和一个可点击的按钮。
请注意,停靠面板可以水平或垂直填充。 您不能同时使用这两种对齐方式。 停靠面板的方向在设置 DockPanel 中的第一个控件时自动设置。 如果第一个控件的 Dock 属性设置为 Top 或 Bottom ,则整个 DockPanel 将垂直定向,反之亦然。
堆叠面板 堆叠面板是最常用的控件之一,因为它们简单且易于使用。 堆叠面板将子控件水平或垂直对齐。 如下所示,您只需设置其方向,类将处理其余部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = Orientation.Vertical)]
public Orientation Orientation { get ; set ; }
protected override void Initialize ()
{
var firstNameTextBox = new TextBox
{
Margin = 5 ,
Text = "First Name..." ,
Width = 200
};
var lastNameTextBox = new TextBox
{
Margin = 5 ,
Text = "Last Name..." ,
Width = 200
};
var isMarriedCheckBox = new CheckBox
{
Text = "Is Married?" ,
Margin = 5 ,
};
var submitButton = new Button
{
Text = "Submit" ,
Margin = 5
};
var stackPanel = new StackPanel
{
Orientation = Orientation ,
HorizontalAlignment = HorizontalAlignment . Right ,
VerticalAlignment = VerticalAlignment . Bottom ,
BackgroundColor = Color . FromArgb ( 80 , Color . Gold ),
Margin = 20
};
stackPanel . AddChild ( firstNameTextBox );
stackPanel . AddChild ( lastNameTextBox );
stackPanel . AddChild ( isMarriedCheckBox );
stackPanel . AddChild ( submitButton );
Chart . AddControl ( stackPanel );
}
public override void Calculate ( int index )
{
}
}
}
创建指标实例后,您应该会在主图表的右下角看到一个水平堆叠面板,其中包含两个文本字段和一个“提交”按钮。
换行面板 换行面板与堆叠面板基本相同。 然而,当换行面板没有足够的空间容纳所有元素时,它会自动将剩余控件换行到Y轴上的下一行。
网格 可以将网格视为具有固定列数和行数的电子表格。 使用网格时,您可以将控件添加到每个单独的单元格中。
如下所示,当您创建 Grid 类的实例时,您将其行数和列数作为 integer 参数传递。 当添加新的子控件或控件时,您同样需要指定子行数和子列数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter("Grid Rows #", DefaultValue = 10)]
public int GridRowsNumber { get ; set ; }
[Parameter("Grid Columns #", DefaultValue = 2)]
public int GridColumnsNumber { get ; set ; }
protected override void Initialize ()
{
var grid = new Grid ( GridRowsNumber , GridColumnsNumber )
{
BackgroundColor = Color . Gold ,
Opacity = 0.6 ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center ,
ShowGridLines = true
};
for ( int iRow = 0 ; iRow < GridRowsNumber ; iRow ++ )
{
for ( int iColumn = 0 ; iColumn < GridColumnsNumber ; iColumn ++ )
{
grid . AddChild ( new TextBlock
{
Text = string . Format ( "Row {0} and Column {1}" , iRow , iColumn ),
Margin = 5 ,
ForegroundColor = Color . Black ,
FontWeight = FontWeight . ExtraBold
}, iRow , iColumn );
}
}
Chart . AddControl ( grid );
}
public override void Calculate ( int index )
{
}
}
}
创建上述指标的实例时,您应该会在图表中心看到一个10x2的网格。
在价格和时间坐标内定位控件 除了面板控件外,cTrader还允许直接在图表区域中为控件指定价格和时间坐标。 AddControl () 和 MoveControl () 方法为算法开发者提供了此功能。
根据您的偏好,使用以下方法重载来管理图表控件的坐标。
将图表控件添加到图表或指标区域中的绝对柱索引和价格(x, y)坐标上。
void AddControl ( ControlBase control , int barIndex , double y )
将图表控件移动到图表或指标区域中的绝对柱索引和价格(x, y)坐标上。
void MoveControl ( ControlBase control , int barIndex , double y )
将图表控件添加到图表或指标区域中的绝对时间和价格(x, y)坐标上。
void AddControl ( ControlBase control , DateTime time , double y )
将图表控件移动到图表或指标区域中的绝对时间和价格(x, y)坐标上。
void MoveControl ( ControlBase control , DateTime time , double y )
将图表控件添加到图表或指标区域中的绝对时间(x)坐标上。
void AddControl ( ControlBase control , DateTime time )
将图表控件移动到图表或指标区域中的绝对时间(x)坐标上。
void MoveControl ( ControlBase control , DateTime time )
将图表控件添加到图表或指标区域中的绝对柱索引(x)坐标上。
void AddControl ( ControlBase control , int barIndex )
将图表控件移动到图表或指标区域中的绝对柱索引(x)坐标上。
void MoveControl ( ControlBase control , int barIndex )
将图表控件添加到图表或指标区域中的绝对价格(y)坐标上。
void AddControl ( ControlBase control , double y )
将图表控件移动到图表或指标区域中的绝对价格(y)坐标上。
void MoveControl ( ControlBase control , double y )
ControlBase 参数类可以包括任何其他从属类(Control、Button 等), 以便根据上述签名调用方法。
以下cBot示例将 点击我! 按钮添加到图表上的最后一根柱上方。 按钮会随着每根新柱的添加而向前移动。 点击按钮后,屏幕上会出现一个消息框。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using cAlgo.API ;
using cAlgo.API.Collections ;
using cAlgo.API.Indicators ;
using cAlgo.API.Internals ;
namespace cAlgo.Robots
{
[Robot(AccessRights = AccessRights.None)]
public class ButtonTest : Robot
{
[Parameter(DefaultValue = "Hello world!")]
public string Message { get ; set ; }
Button button ;
protected override void OnStart ()
{
button = new Button
{
Text = "Click me!"
};
button . Click += Button_Click ;
Chart . AddControl ( button , Bars . Count - 1 );
}
protected override void OnBar ()
{
Chart . MoveControl ( button , Bars . Count - 1 );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
MessageBox . Show ( Message , "Title/Caption" );
}
}
}
警告
由于可能的性能问题,图表上要添加的根控件数量限制为100。 此限制仅适用于一个算法实例以及附加到价格和柱的控件。
填充和边距属性 Margin 属性定义了 Control 对象与其父对象(图表、面板、边框等)之间的空间。
反过来,Padding 属性决定了控件内容与其边框之间的空间。 您可以调整属性值,使其在不同侧面上各不相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
[Parameter(DefaultValue = "Click Me")]
public string Text { get ; set ; }
[Parameter(DefaultValue = 0)]
public double Left { get ; set ; }
[Parameter(DefaultValue = 0)]
public double Top { get ; set ; }
[Parameter(DefaultValue = 0, Group = "Margin")]
public double LeftMargin { get ; set ; }
[Parameter(DefaultValue = 0, Group = "Margin")]
public double TopMargin { get ; set ; }
[Parameter(DefaultValue = 0, Group = "Margin")]
public double RightMargin { get ; set ; }
[Parameter(DefaultValue = 0, Group = "Margin")]
public double BottomMargin { get ; set ; }
[Parameter(DefaultValue = 5, Group = "Padding")]
public double LeftPadding { get ; set ; }
[Parameter(DefaultValue = 5, Group = "Padding")]
public double TopPadding { get ; set ; }
[Parameter(DefaultValue = 5, Group = "Padding")]
public double RightPadding { get ; set ; }
[Parameter(DefaultValue = 5, Group = "Padding")]
public double BottomPadding { get ; set ; }
protected override void Initialize ()
{
var button = new Button
{
Text = Text ,
Left = Left ,
Top = Top ,
Margin = new Thickness ( LeftMargin , TopMargin , RightMargin , BottomMargin ),
Padding = new Thickness ( LeftPadding , TopPadding , RightPadding , BottomPadding )
};
button . Click += Button_Click ;
var canvas = new Canvas ();
canvas . AddChild ( button );
Chart . AddControl ( canvas );
}
private void Button_Click ( ButtonClickEventArgs obj )
{
obj . Button . Text = "You clicked me, thanks" ;
}
public override void Calculate ( int index )
{
}
}
}
此指标的实例将在图表的左上角创建一个灰色的 点击我 按钮。 修改 添加实例 或 修改参数 窗口中的参数,以查看不同的边距和填充值如何改变控件的显示方式。
样式 使用样式时,您可以为几种不同类型的控件赋予相似的外观。 这在处理大量(五个或更多)控件时特别有用。
Style 类允许为控件的不同属性(如 Margin 或 BackgroundColor )设置值。 之后,您可以将这些值作为模板重复用于多个其他控件。
我们也可以完全不使用 Style 类为多个控件创建一致的外观。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
protected override void Initialize ()
{
var firstTextBox = new TextBox
{
ForegroundColor = Color . Red ,
Margin = 5 ,
FontFamily = "Cambria" ,
FontSize = 12 ,
Text = "Type..." ,
Width = 150
};
var secondTextBox = new TextBox
{
ForegroundColor = Color . Red ,
Margin = 5 ,
FontFamily = "Cambria" ,
FontSize = 12 ,
Text = "Type..." ,
Width = 150
};
var thirdTextBox = new TextBox
{
ForegroundColor = Color . Red ,
Margin = 5 ,
FontFamily = "Cambria" ,
FontSize = 12 ,
Text = "Type..." ,
Width = 150
};
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( firstTextBox );
panel . AddChild ( secondTextBox );
panel . AddChild ( thirdTextBox );
Chart . AddControl ( panel );
}
public override void Calculate ( int index )
{
}
}
}
以下是使用 Style 类如何简化处理多个控件的方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
protected override void Initialize ()
{
var textBoxStyle = new Style ();
textBoxStyle . Set ( ControlProperty . ForegroundColor , Color . Red );
textBoxStyle . Set ( ControlProperty . Margin , 5 );
textBoxStyle . Set ( ControlProperty . FontFamily , "Cambria" );
textBoxStyle . Set ( ControlProperty . FontSize , 12 );
textBoxStyle . Set ( ControlProperty . Width , 150 );
var firstTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var secondTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var thirdTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( firstTextBox );
panel . AddChild ( secondTextBox );
panel . AddChild ( thirdTextBox );
Chart . AddControl ( panel );
}
public override void Calculate ( int index )
{
}
}
}
如果您启动各自的指标实例,上述两个代码片段应显示相同的控件。
您还可以使用 Style 类根据控件的状态更改其外观。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 using cAlgo.API ;
namespace ChartControlsTest
{
[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
public class ChartControls : Indicator
{
protected override void Initialize ()
{
var textBoxStyle = new Style ();
textBoxStyle . Set ( ControlProperty . ForegroundColor , Color . Red );
textBoxStyle . Set ( ControlProperty . Margin , 5 );
textBoxStyle . Set ( ControlProperty . FontFamily , "Cambria" );
textBoxStyle . Set ( ControlProperty . FontSize , 12 );
textBoxStyle . Set ( ControlProperty . Width , 150 );
// Here we change the foreground color to Yellow if mouse hover over the textbox
textBoxStyle . Set ( ControlProperty . ForegroundColor , Color . Yellow , ControlState . Hover );
var firstTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var secondTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var thirdTextBox = new TextBox
{
Text = "Type..." ,
Style = textBoxStyle
};
var panel = new StackPanel
{
Orientation = Orientation . Vertical ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
panel . AddChild ( firstTextBox );
panel . AddChild ( secondTextBox );
panel . AddChild ( thirdTextBox );
Chart . AddControl ( panel );
}
public override void Calculate ( int index )
{
}
}
}
图像 Image 控件可用于显示本地存储的图像。 Image 控件使用 .NET Bitmap 类,这意味着它支持大多数流行的图像格式,如下所示:
.PNG .JPG .BMP .GIF .TIFF 请参阅 .NET Bitmap 类 文档 以了解更多信息。
要使用 Image 控件,请将其 Source 属性设置为字节数组(byte [] )中的图像文件数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 using cAlgo.API ;
using System.IO ;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)]
public class ImageSample : Indicator
{
[Parameter("Image File Path")]
public string ImageFilePath { get ; set ; }
protected override void Initialize ()
{
if ( File . Exists ( ImageFilePath ) is false )
{
Print ( $"Image not found: {ImageFilePath}" );
return ;
}
var imageBytes = File . ReadAllBytes ( ImageFilePath );
var image = new Image
{
Source = imageBytes ,
Width = 200 ,
Height = 200 ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
Chart . AddControl ( image );
}
public override void Calculate ( int index )
{
}
}
}
启动上述指标的实例后,您应该不会在主图表上看到任何新内容。 但是,输入一个有效的文件路径作为(图像文件路径)参数的值,您应该会看到所选图像显示在屏幕中央。
您还可以使用项目资源来存储图像并通过 Image 控件显示它们。 为此,请在 Visual Studio 中打开项目资源并切换到 资源 选项卡。 在其中创建一个新资源并添加现有图像。 之后,您将能够通过 Project_Name_Space . Properties . Resources . _Image_Name 属性在任何 Image 控件中使用此图像作为源。
例如,复制以下图像并将其保存为系统上的 "image.png":
在 cTrader 中创建一个 新指标 ,将其名称设置为 "Image Sample",并通过 Visual Studio 打开它。 之后,将徽标指标项目添加为资源。 为此,右键单击您的项目,选择 属性 并点击 资源 ,然后点击 创建和管理程序集资源 。 将 logo.png 文件复制到新打开的选项卡中。
将以下代码复制到您的指标主源代码文件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 using cAlgo.API ;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class ImageSample : Indicator
{
protected override void Initialize ()
{
var image = new Image
{
Source = Image_Sample . Properties . Resources . logo ,
Width = 200 ,
Height = 200 ,
HorizontalAlignment = HorizontalAlignment . Center ,
VerticalAlignment = VerticalAlignment . Center
};
Chart . AddControl ( image );
}
public override void Calculate ( int index )
{
}
}
}
创建此指标的实例后,您应该会看到以下输出。