Controls allows you to interact with your indicator/cBot user, you can easily create basic to advanced UI controls on a chart.
You can use different controls that is part of controls like button, text block, text box, check box, shapes, or you can build your own custom controls by combining other controls.
The two are very different, controls adds interaction capability to your cBots/Indicators while chart objects/drawings allows you to draw something on the chart.
Chart controls derive from ControlBase class, while Chart objects are derived from ChartObject base class.
The other major difference is in their positioning, for chart controls you can statically position them on chart by using different alignment options, while chart objects uses X (Time) and Y (Price) coordinates for positioning except ChartStaticText which is a chart object but uses alignment options like controls.
Like chart objects/drawings you can add controls on both main chart or it's indicator windows.
To add a control on an indicator window you have to use that indicator area instead of main chart area, example:
Usually when you use controls you may want to place several of them on a group and then add them on a chart, to do this you can use Panels.
A panel is a control, but it's content is other controls, they can contain one or more controls, all panels are derived from Panel base class which itself derives from Control class like all other controls.
There are five different types of panels available:
Canvas
DockPanel
Grid
StackPanel
WrapPanel
Each of them uses different types of layout or positioning strategy that you can use based on your need.
Canvas is a panel that allows you to position your controls based on X and Y coordinates on a chart, these X and Y coordinates are different from the one used by chart objects/drawing.
The X and Y coordinate that is used by Canvas is based on numeric values and starts at 0,0 from top left most of the chart.
usingcAlgo.API;namespaceChartControlsTest{[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]publicclassChartControls:Indicator{[Parameter(DefaultValue = "Click Me")]publicstringText{get;set;}[Parameter(DefaultValue = 0)]publicdoubleLeft{get;set;}[Parameter(DefaultValue = 0)]publicdoubleTop{get;set;}[Parameter(DefaultValue = 0)]publicdoubleMargin{get;set;}[Parameter(DefaultValue = 10)]publicdoublePadding{get;set;}protectedoverridevoidInitialize(){varbutton=newButton{Text=Text,Left=Left,Top=Top,Margin=Margin,Padding=Padding};button.Click+=Button_Click;varcanvas=newCanvas();// We add our button control to canvas panel//Instead of directly adding it to Chartcanvas.AddChild(button);// And then we add our panel to chart// Which contains our button controlChart.AddControl(canvas);}privatevoidButton_Click(ButtonClickEventArgsobj){obj.Button.Text="You clicked me, thanks";}publicoverridevoidCalculate(intindex){}}}
Build the above indicator and attach it on chart, then play with Left and Top parameters.
The Top property of a control allows you to set the distance of the control from top of the chart and the Left property of a control allows you to set the distance of control from left of the chart, this way you can position your control vertically and horizontally.
We also used two new properties, Padding and Margin, the former is the distance of a control inner content from it's outer borders and the later is the distance of a control from left, top, right, and bottom of it's parent.
You can use Padding and Margin on all Panels not just Canvas, and they are really helpful when you want to manage the spacing between your controls.
You might thinking that it's very hard to properly position lots of controls with Canvas, you are right, that why we have other Panels.
Canvas is only useful if you are using it for drawing, or positioning something anywhere on the chart.
usingcAlgo.API;namespaceChartControlsTest{[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]publicclassChartControls:Indicator{[Parameter(DefaultValue = Dock.Top)]publicDockTextBoxDock{get;set;}[Parameter(DefaultValue = Dock.Bottom)]publicDockButtonDock{get;set;}privateTextBox_textBox;protectedoverridevoidInitialize(){_textBox=newTextBox{Margin=5,Text="Write here...",ForegroundColor=Color.Yellow,Dock=TextBoxDock,Width=200};varbutton=newButton{Text="Tell what I wrote?",Dock=ButtonDock,Width=200};button.Click+=Button_Click;vardockPanel=newDockPanel{HorizontalAlignment=HorizontalAlignment.Center,VerticalAlignment=VerticalAlignment.Center,};dockPanel.AddChild(_textBox);dockPanel.AddChild(button);Chart.AddControl(dockPanel);}privatevoidButton_Click(ButtonClickEventArgsobj){obj.Button.Text=$"You wrote: {_textBox.Text}";}publicoverridevoidCalculate(intindex){}}}
A dock panel can either be horizontally populated or vertically, you can't use both at the same time.
The orientation is set automatically when you add the first control on it, if the first control Dock is set to either Top or Bottom then it will be vertically oriented otherwise horizontally.
It's almost identical to Stack Panel, the only difference is that when there is not enough space it wraps the remaining controls to the next line or to the bottom.
Grid divides it's spaces into rows and columns, then you can add a control on each of it's cells.
When you create an instance of Grid you pass the number of it's rows and columns, after that whenever you add a child or control on it you have to also set the number of child rows and columns.
What if you want to give a similar look to several different types of controls? you can set each control properties separately, it might not a big issue if you are dealing with few controls, but what if you were dealing with tens or even more controls?
Style allows you to set values for different properties of controls like Margin or BackgroundColor once and then reuse it like a template for multiple controls.
Let's try to create three textbox with same text color, font, and background, you can do it without using style like this:
usingcAlgo.API;namespaceChartControlsTest{[Indicator(IsOverlay = true, AccessRights = AccessRights.None)]publicclassChartControls:Indicator{protectedoverridevoidInitialize(){vartextBoxStyle=newStyle();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 textboxtextBoxStyle.Set(ControlProperty.ForegroundColor,Color.Yellow,ControlState.Hover);varfirstTextBox=newTextBox{Text="Type...",Style=textBoxStyle};varsecondTextBox=newTextBox{Text="Type...",Style=textBoxStyle};varthirdTextBox=newTextBox{Text="Type...",Style=textBoxStyle};varpanel=newStackPanel{Orientation=Orientation.Vertical,HorizontalAlignment=HorizontalAlignment.Center,VerticalAlignment=VerticalAlignment.Center};panel.AddChild(firstTextBox);panel.AddChild(secondTextBox);panel.AddChild(thirdTextBox);Chart.AddControl(panel);}publicoverridevoidCalculate(intindex){}}}
You can also use your project resources for storing images and then using them on an Image control.
To add an image to your project resources, open your project "Properties" in Visual Studio and then go to "Resources" tab, there create resources for your project and add an existing image.
After adding an image to your project resources you can use it on an Image control as a source.
To access the added image resource use Project_Name_Space.Properties.Resources._Image_Name.
As an example copy the below image and save it as "image.png" on your system:
Then create a new indicator on cTrader, set it's name to Image Sample, open it with Visual Studio, and add the image to your indicator project as a resource.
Copy the below code to your indicator main source code file: