Перейти к содержанию

Элементы управления

Элементы управления обеспечивают определенные взаимодействия с участием сиБотов, индикаторов и плагинов. Используя приведенное ниже руководство, вы можете легко создавать базовые и расширенные элементы управления пользовательского интерфейса непосредственно на графике.

Существует несколько встроенных классов, которые представляют популярные элементы управления, такие как кнопки, текстовые блоки, текстовые поля и фигуры. Однако вы также можете создавать пользовательские элементы управления.

Рассмотрим следующий пример:

 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)
        {
        }
    }
}

Если вы создадите вышеуказанный индикатор и создадите экземпляр, вы должны увидеть серую кнопку Click me прямо в центре графика.

Разница между элементами управления и объектами графика

В предыдущем разделе мы уже рассмотрели объекты графика. Элементы управления позволяют пользователям взаимодействовать с сиБотами и индикаторами. И наоборот, объекты графика дают возможность нарисовать что-то на торговом графике или в отдельном окне вывода индикатора.

Элементы управления графиком наследуются от класса 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)
        {
        }
    }
}

После создания экземпляра индикатора вы должны увидеть кнопку Click me в окне вывода индикатора.

ColorPicker

Элемент управления ColorPicker позволяет трейдерам выбирать предпочитаемый цвет для ключевых элементов или объектов в cTrader. Например, разработчик может интегрировать элемент управления ColorPicker в сиБота, который рисует линии тренда, чтобы пользователи могли выбрать предпочитаемый цвет для каждой линии тренда. Такая настройка облегчает трейдерам различение между различными типами линий тренда.

Плагин, который добавляет индикаторы на графики, также может реализовать элемент управления 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
        }
    }        
}

Image title

DropZone

Элемент управления DropZone позволяет трейдерам выполнять действия перетаскивания с участием сиБотов, индикаторов или плагинов. Чтобы реализовать этот элемент управления в вашем алгоритме, используйте класс DropZone. Элементом управления DropZone можно манипулировать, как и любым другим элементом управления.

Когда пользователь перетаскивает совместимый файл или папку в поле, генерируется событие Dropped. Когда пользователь перетаскивает папку или несколько папок в поле, обрабатываются и копируются только совместимые файлы с указанными расширениями в FilterExtensions.

Примечание

Перетаскиваемые файлы обычно копируются и сохраняются в этом месте: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected Files\

Расположение для экземпляров сиБотов отличается от вышеуказанного: ..\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!");
        }
    }
}

Image title

ProgressBar

Элемент управления ProgressBar отображает прогресс текущей операции. Индикаторы выполнения делают алгоритмы более удобными для пользователя и помогают управлять ожиданиями трейдеров относительно времени ожидания определенных операций.

cTrader Algo API позволяет разработчикам добавлять два типа элементов управления ProgressBar: бесконечный элемент управления и определенный элемент управления.

Бесконечный элемент управления

Вы можете использовать бесконечный элемент управления в следующих ситуациях:

  • Вы не можете определить время ожидания операции.
  • Вы не можете обнаружить прогресс операции.
  • Вы не хотите указывать, сколько времени займет операция.

Image title

Определенный элемент управления

Вы можете использовать этот элемент управления, когда можете определить время ожидания операции и хотите, чтобы пользователи видели индикатор на основе этого времени.

Чтобы отобразить прогресс операции, используйте свойство Value для установки значения. Чтобы установить процент индикатора выполнения, используйте свойства Minimum и Maximum.

Image title

Приведенный ниже код плагина показывает, как создать индикатор выполнения, используя как бесконечный, так и определенный (зеленый) элементы управления:

 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)
        {
        }
    }
}

Image title

cTrader Algo API предоставляет интерфейс OpenFolderDialog, позволяющий пользователям указать папку для алгоритма. Когда пользователь выбирает папку в появившемся окне, все файлы и папки с файлами внутри выбранной папки копируются в папку Selected files алгоритма.

Совет

Используйте функциональность OpenFolderDialog, когда вам нужно загрузить папку, содержащую критически важные файлы данных, резервные копии или файлы конфигурации, пользовательские индикаторы или скрипты.

Выбранные файлы и папки обычно копируются в папку Selected files, потому что алгоритм может работать с элементами внутри этой папки, даже когда его AccessRights установлен на None.

Примечание

Папка Selected files алгоритма обычно находится по этому пути: ..\Documents\cAlgo\Data\{AlgoType}\{AlgoName}\Selected files\

Папка 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)
        {
        }
    }
}

Image title

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:

 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 отличаются от тех, которые используются объектами графика или рисунками. Координаты X и Y, используемые классом Canvas, представляют собой числовые значения, начинающиеся с (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)
        {
        }
    }
}

После создания экземпляра индикатора вы должны увидеть горизонтальную панель стека с двумя текстовыми полями и кнопкой Submit в правом нижнем углу основного графика.

Панель с переносом

Панели с переносом в основном идентичны панелям стека. Однако, когда недостаточно места для размещения всех элементов панели с переносом, она автоматически перенесет оставшиеся элементы управления на следующую строку по оси 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).

1
void AddControl(ControlBase control, int barIndex, double y)

Чтобы переместить элемент управления графика на график или область индикатора по абсолютному индексу бара и координатам цены (x, y).

1
void MoveControl(ControlBase control, int barIndex, double y)

Чтобы добавить элемент управления графика на график или область индикатора по абсолютному времени и координатам цены (x, y).

1
void AddControl(ControlBase control, DateTime time, double y)

Чтобы переместить элемент управления графика на график или область индикатора по абсолютному времени и координатам цены (x, y).

1
void MoveControl(ControlBase control, DateTime time, double y)

Чтобы добавить элемент управления графика на график или область индикатора по абсолютной координате времени (x).

1
void AddControl(ControlBase control, DateTime time)

Чтобы переместить элемент управления графика на график или область индикатора по абсолютной координате времени (x).

1
void MoveControl(ControlBase control, DateTime time)

Чтобы добавить элемент управления графика на график или область индикатора по абсолютной координате индекса бара (x).

1
void AddControl(ControlBase control, int barIndex)

Чтобы переместить элемент управления графика на график или область индикатора по абсолютной координате индекса бара (x).

1
void MoveControl(ControlBase control, int barIndex)

Чтобы добавить элемент управления графика на график или область индикатора по абсолютной координате цены (y).

1
void AddControl(ControlBase control, double y)

Чтобы переместить элемент управления графика на график или область индикатора по абсолютной координате цены (y).

1
void MoveControl(ControlBase control, double y)

Класс параметров ControlBase может включать любой другой подчиненный класс (Control, Button и т. д.), чтобы метод вызывался в соответствии с вышеуказанными сигнатурами.

Следующий пример сиБота добавляет кнопку Нажми меня! над последним баром на графике. Кнопка перемещается вперед вместе с каждым новым добавленным баром. После нажатия на кнопку на экране появляется окно сообщения.

 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 File Path), и вы должны увидеть выбранное изображение, отображаемое в центре экрана.

Вы также можете использовать ресурсы вашего проекта для хранения изображений и их отображения через элемент управления Image. Для этого откройте ресурсы проекта в Visual Studio и переключитесь на вкладку Resources. В ней создайте новый ресурс и добавьте существующее изображение. После этого вы сможете использовать это изображение в качестве источника в любом элементе управления Image через свойство Project_Name_Space.Properties.Resources._Image_Name.

В качестве примера скопируйте изображение ниже и сохраните его как "image.png" в вашей системе:

Image title

Создайте новый индикатор в cTrader, задайте ему имя "Image Sample" и откройте его через Visual Studio. После этого добавьте проект индикатора логотипа в качестве ресурса. Для этого щелкните правой кнопкой мыши по вашему проекту, выберите Properties и нажмите Resources, затем нажмите Create and manage assembly resources. Скопируйте файл 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)
        {
        }
    }
}

После создания экземпляра этого индикатора вы должны увидеть следующий результат.

Image title

Примечание

Максимальный размер изображений составляет 10 МБ.