Will Button and Canvas duplicated and overlapped

Created at 22 Jan 2022, 04:23
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
Capt.Z-Fort.Builder's avatar

Capt.Z-Fort.Builder

Joined 03.06.2020

Will Button and Canvas duplicated and overlapped
22 Jan 2022, 04:23


Hello support team,

I have the below code. I want the price up/down to define the position (top/bottom) of the button and canvas, which is working fine. And the button is a switch to display the canvas, and it also works well.

But I want to know:

1. As the market opens, price ticks calucate going on, 'Will more buttons be added and overlapped in each tick-Calculate?'

2. I see the code adding a new button and canvas in each calculation, will this make trouble to memory RAM exhausted? 

3. I tried to move button = new button {....}  and canvas = new canvas {....} blocks to Initialize(), but that would not let the click work correctly. 

Please advice, 

Thanks,

L

using cAlgo.API;

namespace cAlgo 
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, ScalePrecision = 2, AccessRights = AccessRights.None)]
    public class BestButton : Indicator
    {
        public bool bChtText = true;
        private Button button;
        private Canvas canvas;

        protected override void Initialize()
        {

        }

        public override void Calculate(int index)
        {
            if (IsLastBar  )   
            {
                MsgBrd();
            }
        }

        private void MsgBrd()
        {
            //Chart.RemoveControl(button); //Without the removal, will more buttons  be added and overlapped in each tick-Calculate?
            button = new Button
            {   Text = "Button", FontSize = 50,
                Margin = "1 5 0 5", Padding = "2 1 2 1", Height = 115,
                HorizontalAlignment = HorizontalAlignment.Left
            };
            //Chart.RemoveControl(canvas); //Without the removal, will more canvases be added and overlapped in each tick-Calculate?
            canvas = new Canvas
            {   HorizontalAlignment = HorizontalAlignment.Center,
                Width = 400, Height = 115, Margin = 5, Opacity = 0.1
            };

            if   (LastBarUpOrDown())
            {
                button.VerticalAlignment = VerticalAlignment.Top;
                button.BackgroundColor = Color.FromHex("#4488FF88");
                button.ForegroundColor = Color.FromHex("#9988FF88");
                canvas.BackgroundColor = Color.SandyBrown;
                canvas.VerticalAlignment = VerticalAlignment.Top;
            }
            else
            {
                button.VerticalAlignment = VerticalAlignment.Bottom;
                button.BackgroundColor = Color.FromHex("#44FF8888");
                button.ForegroundColor = Color.FromHex("#99FF8888");
                canvas.BackgroundColor = Color.DeepSkyBlue;
                canvas.VerticalAlignment = VerticalAlignment.Bottom;
            }

            Chart.AddControl(button);
            if (bChtText) { Chart.AddControl(canvas); }
            button.Click += button_Click;
        }

        private void button_Click(ButtonClickEventArgs obj)
        {   Chart.RemoveControl(button); Chart.RemoveControl(canvas); bChtText = bChtText ? false : true; MsgBrd(); }

        private bool LastBarUpOrDown()
        {   return Bars.Last(0).Close > Bars.Last(0).Open ? true : false; }
    }
}

 


@Capt.Z-Fort.Builder
Replies

amusleh
24 Jan 2022, 09:00

Hi,

I will answer each of your point:

1. Yes, it will, you should not create a new button or canvas on each tick/bar

2. It will, because any control you create will live on memory as long as you remove it from chart or remove your indicator from chart

3. You should use OnInitilaize method and only change the control properties based on your criteria.

Here is your indicator code that is properly written:

using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, ScalePrecision = 2, AccessRights = AccessRights.None)]
    public class BestButton : Indicator
    {
        private Button _button;
        private Canvas _canvas;

        protected override void Initialize()
        {
            _button = new Button
            {
                Text = "Button",
                FontSize = 50,
                Margin = "1 5 0 5",
                Padding = "2 1 2 1",
                Height = 115,
                HorizontalAlignment = HorizontalAlignment.Left
            };

            _button.Click += button_Click;

            Chart.AddControl(_button);

            _canvas = new Canvas
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                Width = 400,
                Height = 115,
                Margin = 5,
                Opacity = 0.1
            };

            Chart.AddControl(_canvas);
        }

        public override void Calculate(int index)
        {
            if (IsLastBar)
            {
                MsgBrd();
            }
        }

        private void MsgBrd()
        {
            if (LastBarUpOrDown())
            {
                _button.VerticalAlignment = VerticalAlignment.Top;
                _button.BackgroundColor = Color.FromHex("#4488FF88");
                _button.ForegroundColor = Color.FromHex("#9988FF88");
                _canvas.BackgroundColor = Color.SandyBrown;
                _canvas.VerticalAlignment = VerticalAlignment.Top;
            }
            else
            {
                _button.VerticalAlignment = VerticalAlignment.Bottom;
                _button.BackgroundColor = Color.FromHex("#44FF8888");
                _button.ForegroundColor = Color.FromHex("#99FF8888");
                _canvas.BackgroundColor = Color.DeepSkyBlue;
                _canvas.VerticalAlignment = VerticalAlignment.Bottom;
            }
        }

        private void button_Click(ButtonClickEventArgs obj)
        {
            _canvas.IsVisible = _canvas.IsVisible ? false : true;
        }

        private bool LastBarUpOrDown()
        {
            return Bars.Last(0).Close > Bars.Last(0).Open ? true : false;
        }
    }
}

 


@amusleh

Capt.Z-Fort.Builder
24 Jan 2022, 18:39 ( Updated at: 24 Jan 2022, 18:41 )

RE:

Thank you Amusleh,  I believe this is the right way to process the code. 

Well, in my practice, the following question is,  there are multiple TextBlocks in a Grid or several Grids,  and they all need to change ForegroundColors and Positions by the price up or down. Is there any quick way, I can change all the TextBlocks' ForegroundColor and other properties rather than one by one which makes the code extremely long?

Thanks again in advance.

amusleh said:

Hi,

I will answer each of your point:

1. Yes, it will, you should not create a new button or canvas on each tick/bar

2. It will, because any control you create will live on memory as long as you remove it from chart or remove your indicator from chart

3. You should use OnInitilaize method and only change the control properties based on your criteria.

Here is your indicator code that is properly written:

using cAlgo.API;

namespace cAlgo
{
   ...
}

 

 


@Capt.Z-Fort.Builder

amusleh
25 Jan 2022, 08:22

RE: RE:

TheNiatpac said:

Thank you Amusleh,  I believe this is the right way to process the code. 

Well, in my practice, the following question is,  there are multiple TextBlocks in a Grid or several Grids,  and they all need to change ForegroundColors and Positions by the price up or down. Is there any quick way, I can change all the TextBlocks' ForegroundColor and other properties rather than one by one which makes the code extremely long?

Thanks again in advance.

amusleh said:

Hi,

I will answer each of your point:

1. Yes, it will, you should not create a new button or canvas on each tick/bar

2. It will, because any control you create will live on memory as long as you remove it from chart or remove your indicator from chart

3. You should use OnInitilaize method and only change the control properties based on your criteria.

Here is your indicator code that is properly written:

using cAlgo.API;

namespace cAlgo
{
   ...
}

 

 

Hi,

You can put all the controls inside a collection like list and then change them one by one or use a parent custom control.

There is no other way except updating each control on a sequential order.


@amusleh

Capt.Z-Fort.Builder
25 Jan 2022, 15:29

RE: RE: RE:

Hi Amusleh,

Thanks very much for the hints, I've made this code to define a group of buttons, by c# collections.

Would you mind showing me the technique to do the same job via 'parent custom control'?

L

using System.Collections.Generic;
using cAlgo.API;


namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Buttons : Indicator
    {

        private Button DS_Btn = new Button { Text = "DS", VerticalAlignment = VerticalAlignment.Top };
        private Button DL_Btn = new Button { Text = "DL", VerticalAlignment = VerticalAlignment.Bottom };
        private Button BM_Btn = new Button { Text = "BM", VerticalAlignment = VerticalAlignment.Center };

        private readonly Color clrBtnFrtMd = Color.FromHex("#FF000000"); //ChartButton FrontColor
        private readonly Color clrBtnBktMd = Color.FromHex("#55CFCFCF"); //ChartButton Background
        private readonly Color clrBrdFrtUp = Color.FromHex("#EE88FF88"); //Red   BackGround
        private readonly Color clrBrdFrtDn = Color.FromHex("#EEFF8888"); //Green BackGround
        
        private bool _DS, _DL, _BM; 

        protected override void Initialize()
        {
            //Add-Controls: Buttons
            var buttons = new List<Button>();
            buttons.Add(DS_Btn);
            buttons.Add(DL_Btn);
            buttons.Add(BM_Btn);
            foreach (var button in buttons)
            {
                button.Margin = "0 1 0 1";
                button.Padding = "4 0 4 0";
                button.Height = 16;
                button.FontSize = 9;
                button.IsVisible = true;
                button.ForegroundColor = clrBtnFrtMd;
                button.BackgroundColor = clrBtnBktMd;
                button.HorizontalAlignment = HorizontalAlignment.Center;
            }

            IndicatorArea.AddControl(DS_Btn); DS_Btn.Click += DS_Btn_Click;
            IndicatorArea.AddControl(DL_Btn); DL_Btn.Click += DL_Btn_Click;
            IndicatorArea.AddControl(BM_Btn); BM_Btn.Click += BM_Btn_Click;
        }

        public override void Calculate(int index)
        {
        }
        
        private void DS_Btn_Click(ButtonClickEventArgs obj) 
        { _DS = _DS ? false : true; DS_Btn.BackgroundColor = _DS ? clrBrdFrtUp : clrBrdFrtDn; }

        private void DL_Btn_Click(ButtonClickEventArgs obj) 
        { _DL = _DL ? false : true; DL_Btn.BackgroundColor = _DL ? clrBrdFrtUp : clrBrdFrtDn; }

        private void BM_Btn_Click(ButtonClickEventArgs obj) 
        { _BM = _BM ? false : true; BM_Btn.BackgroundColor = _BM ? clrBrdFrtUp : clrBrdFrtDn; }

    }
}

amusleh said:

TheNiatpac said:

Thank you Amusleh,  I believe this is the right way to process the code. 

Well, in my practice, the following question is,  there are multiple TextBlocks in a Grid or several Grids,  and they all need to change ForegroundColors and Positions by the price up or down. Is there any quick way, I can change all the TextBlocks' ForegroundColor and other properties rather than one by one which makes the code extremely long?

Thanks again in advance.

amusleh said:

Hi,

I will answer each of your point:

1. Yes, it will, you should not create a new button or canvas on each tick/bar

2. It will, because any control you create will live on memory as long as you remove it from chart or remove your indicator from chart

3. You should use OnInitilaize method and only change the control properties based on your criteria.

Here is your indicator code that is properly written:

using cAlgo.API;

namespace cAlgo
{
   ...
}

 

 

Hi,

You can put all the controls inside a collection like list and then change them one by one or use a parent custom control.

There is no other way except updating each control on a sequential order.

 


@Capt.Z-Fort.Builder

amusleh
26 Jan 2022, 09:25

Hi,

Here is an example that might help you:

using System.Collections.Generic;
using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Buttons : Indicator
    {
        protected override void Initialize()
        {
            // Change the panel or it's proerpties based on your needs
            var buttonsPanel = new StackPanel
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center
            };

            var myButtonsContainer = new MyButtonsContainer(buttonsPanel);

            myButtonsContainer.AddButton(new Button { Text = "Test Button" });

            Chart.AddControl(myButtonsContainer);

            foreach (var button in myButtonsContainer.GetButtons())
            {
                // Do something with button
            }
        }

        public override void Calculate(int index)
        {
        }
    }

    public class MyButtonsContainer : CustomControl
    {
        private readonly List<Button> _buttons = new List<Button>();

        // You can use any Panel like StackPanel, Grid, etc...
        public MyButtonsContainer(Panel panel)
        {
            ContentPanel = panel;

            AddChild(ContentPanel);
        }

        public Panel ContentPanel { get; private set; }

        public void AddButton(Button button)
        {
            // If you have something in common between buttons you can add it here
            // like event handlers, styles, etc...

            button.Click += Button_Click;

            ContentPanel.AddChild(button);
            _buttons.Add(button);
        }

        private void Button_Click(ButtonClickEventArgs obj)
        {
            obj.Button.Text = "Clicked";
        }

        public IEnumerable<Button> GetButtons()
        {
            return _buttons;
        }
    }
}

You can also check each examples of each control I used above on API references.


@amusleh

Capt.Z-Fort.Builder
26 Jan 2022, 23:05

RE:

Thank you Musleh, much appreciated.

I will use the Collections and List<> way on my case. Both methods need modifying items one by one, just like you said. 

Thanks again, I learned many from you. Hope you have a good day and week. :)

amusleh said:

Hi,

Here is an example that might help you:

using System.Collections.Generic;
using cAlgo.API;

namespace cAlgo
{
 ...
}

You can also check each examples of each control I used above on API references.

 


@Capt.Z-Fort.Builder