Discussion of article "Developing graphical interfaces for Expert Advisors and indicators based on .Net Framework and C#"

MetaQuotes
Moderator
233673
MetaQuotes  

New article Developing graphical interfaces for Expert Advisors and indicators based on .Net Framework and C# has been published:

The article presents a simple and fast method of creating graphical windows using Visual Studio with subsequent integration into the Expert Advisor's MQL code. The article is meant for non-specialist audiences and does not require any knowledge of C# and .Net technology.

MetaTrader 5 strategy tester has a number of features that should be considered by MQL GUI developers. The main one is the fact that the OnChartEvent graphic event processing function is not called at all. This feature is logical since the graphic form involves working with a user in real time. However, it would be extremely interesting to implement a certain type of panels in the tester. These are the so-called trading players allowing users to manually test their trading strategies. For example, the strategy tester generates the current market prices in fast forward, while a user clicks the Buy and Sell buttons simulating trading operations on history. TradePanel that we have developed is exactly this type of panels. Despite its simplicity, it may well be a plain trading player with the most necessary functionality. 

But let's think about how our panel will work in the MetaTrader 5 strategy tester. TradePanel's graphical window exists as an independent Net assembly. Therefore, it does not depend on the current MetaTrader 5 environment or even the terminal itself. Strictly speaking, it can be run from any other program, while even users themselves can launch assemblies located in the exe container.

Thus, our program does not need to call OnChartEvent. Moreover, it is possible to update data in the window and receive new orders from users in any event handling function regularly launched in the strategy tester. OnTick and OnTimer are such functions. The panel works through them. Therefore, although designed for real-time operation, our panel will also work well in the strategy tester. No changes are required for that. Let's check this statement by launching our panel in the tester and performing several deals:

Author: Vasiliy Sokolov

apirakkamjan
60
apirakkamjan  

Thanks, Vasilliy  

NOTE:  In order to to get TradePanel.dll, at Visual Studio's Property Window, you need to right click at TradePanel.sln >  Build. 

andy.maverl
7
andy.maverl  

Hi,


Can this be used with WPF application as well or just window form ?


Thanks

Artur Zas
22138
Artur Zas  
andy.maverl:

Hi,


Can this be used with WPF application as well or just window form ?


Thanks

The code in the example is WinForms specific, but you can easily alter it for use with WPF. You just need to bind to different events on the WPF shell side. The code will be a bit different but the principles will remain the same.

You can also use the code as is if you just use the WinForms window as a host for XAML controls. You can do this with the new XAML Islands. This way you can use all of the modern UWP controls inside a WinForm.

Babak Zolmajd
21
Babak Zolmajd  

Thank you for sharing your information

Can we use these codes in MT4 or only we can use it in MT5

andy.maverl
7
andy.maverl  
Yeah I also have the same question with Babak. Does MQL4 now support native integration with Net framework like mql5 ? Thanks
AlmeidaAlin3
8
AlmeidaAlin3  
awesome! works like a charm. thank you very much!
Kareem Abdelhakim
8055
Kareem Abdelhakim  
Can this library be used with MT4 also ? 
Mano
12
Mano  
Can we attach this .Net app into chart?
Mano
12
Mano  

For MT4, We need to do some changes on MtGuiController.dll. like DLLEXPORT using RGiesecke.DllExport and marshalling input & output parameters.

 // add reference using nuget 
using RGiesecke.DllExport;

        [DllExport("ShowForm", CallingConvention = CallingConvention.StdCall)]
        public static void ShowForm([MarshalAs(UnmanagedType.LPWStr)] string assembly_path, [MarshalAs(UnmanagedType.LPWStr)] string form_name)
        {
            try
            {
                GuiController controller = GetGuiController(assembly_path, form_name);
                string full_path = assembly_path + "/" + form_name;
                m_controllers.Add(full_path, controller);
                controller.RunForm();
            }
            catch(ArgumentException e)
            {
                Type t = e.GetType();
                SendExceptionEvent(e);
            }
        }
        [DllExport("HideForm", CallingConvention = CallingConvention.StdCall)]
        public static void HideForm([MarshalAs(UnmanagedType.LPWStr)] string assembly_path, [MarshalAs(UnmanagedType.LPWStr)] string form_name)
        {
            try
            {
                string full_path = assembly_path + "/" + form_name;
                if (!m_controllers.ContainsKey(full_path))
                    return;
                GuiController controller = m_controllers[full_path];
                controller.DisposeForm();
                m_controllers.Remove(full_path);
            }
            catch(Exception ex)
            {
                SendExceptionEvent(ex);
            }
        }
        [DllExport("SendEvent", CallingConvention = CallingConvention.StdCall)]
        public static void SendEvent([MarshalAs(UnmanagedType.LPWStr)] string el_name, [MarshalAs(UnmanagedType.U4)] int id, [MarshalAs(UnmanagedType.U8)] long lparam, [MarshalAs(UnmanagedType.R8)] double dparam, [MarshalAs(UnmanagedType.LPWStr)] string sparam)
        {            
            SendEventRef(el_name, ref id, ref lparam, ref dparam, sparam);
        }
        [DllExport("ReceiveEvent", CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.LPWStr)]
        public static string ReceiveEvent([MarshalAs(UnmanagedType.I4)] int event_n)
        {
            string json = "";
            int id=0;
            string el_name="", sparam="";
            long lparam=0;
            double dparam=0.0;
            GetEvent(event_n,ref el_name, ref id, ref lparam, ref dparam, ref sparam);
            json = "{ \"el_name\":\"" + el_name + "\",\"id\":" + id + ",\"lparam\":" + lparam + ",\"dparam\":" + dparam + ",\"sparam\":\"" + sparam + "\" }"; 
            return json;
        }
        public static void GetEvent(int event_n, ref string el_name,ref int id,  ref long lparam, ref double dparam, ref string sparam)
        {         
                GuiEvent e = m_global_events[event_n];
                el_name = e.el_name;
                id = (int)e.id;
                lparam = e.lparam;
                dparam = e.dparam;
                sparam = e.sparam;
            
        }
       
        [DllExport("EventsTotal", CallingConvention = CallingConvention.StdCall)]
        public static int EventsTotal()
        {
            return m_global_events.Count;
        }
      


MQL4


#import  "MtGuiController.dll"
void ShowForm(string assembly_path, string form_name);
void HideForm(string assembly_path, string form_name);
void SendEvent(string el_name, int id, long lparam, double dparam, string sparam);
string ReceiveEvent(int event_n); // Returns JSON string.. Use JAson.mqh to Deserialize objects
int EventsTotal();
#import
Pete
9
Pete  

I'm relative new to MQL5 and I learned a lot from this article! Thanks very much!


I have one question. Have been struggling a bit for the past 2 days to figure this out down below.


I have successfully completed each step a couple of times even on another computer but everytime when I try to compile the code I get an error message.


The MQL compiler states : "Undeclared Identifier" for any of the enumerations down below.


public enum GuiEventType
{
    Exception,
    ClickOnElement,
    TextChange,
    ScrollChange
}

If I "comment" these enumerations out from MQL5 then it works accordingly which is interesting since this means that the code works but can't read the enumerations which is my guess?

If someone can help me I would greatly appreciate :)


Thanks,