cTrader göstergeleri ve cBot'ları .NET uygulamaları olduğundan, bunları oluştururken WinForms ve WPF gibi kullanıcı arayüzüyle ilgili çözümler de dahil olmak üzere tüm .NET teknolojilerini kullanabilirsiniz. cTrader, diyaloglar, formlar, Visual Studio WinForms tasarımcısı, üçüncü taraf kullanıcı arayüzü denetimleri ve bileşenleri dahil olmak üzere WinForms ve WPF tarafından sunulan tüm özellikleri destekler.
Not
WinForms veya WPF kullanan algoritmalar yalnızca Windows makinelerinde çalıştırılabilir.
Özel bir WinForms diyaloğu oluşturarak WinForms'un nasıl kullanılabileceğini göstereceğiz. Uyarıları göstermek veya kullanıcı girişi istemek için kullanışlıdırlar.
Projenizi yapılandırma
WinForms'u cBot'larınızda ve göstergelerinizde kullanmadan önce, cBot veya gösterge proje dosyanızda/dosyalarınızda birkaç değişiklik yapmanız gerekecektir. WinForms yalnızca Windows'ta çalıştığı için, projenizin gösterge veya cBot çerçevesinin hedefini .NET'in Windows varyantına değiştirmeniz gerekecektir.
Bunu yapmak için, proje dosyanızı Visual Studio'da açın ve içeriğini aşağıdakilerle değiştirin:
UseWindowsForms etiketini ekledik ve TargetFramework değerini net6.0-windows olarak değiştirdik.
Ardından, AccessRights sınıf parametresinin değerini FullAccess olarak değiştirin. Bu değişiklik yapılmadığı sürece, uzantınızın bir WinForms penceresi açmak için yeterli erişim hakkı olmayacaktır.
Yukarıdaki değişiklikleri yaptıktan sonra projenizi yeniden oluşturun.
Diyalogları kullanma
Neyse ki, WinForms, hata mesajı gösterme, kullanıcıdan onay alma veya bir dosya veya klasör seçme gibi çok çeşitli durumlar için kullanışlı, kullanıma hazır çeşitli diyaloglar içerir.
Aşağıdaki örnek, MessageBox sınıfını ve dosya açma ve kaydetme diyaloglarını kullanır.
MessageBox
System.Windows.Forms.MessageBox sınıfını diğer tüm .NET uygulamalarında kullanıldığı gibi kullanabilirsiniz.
Aşağıdaki kod, standart bir onay kutusunu bir göstergeye ekler:
usingcAlgo.API;usingSystem.Windows.Forms;namespaceWinFormsTest{[Indicator(IsOverlay = true, AccessRights = AccessRights.FullAccess)]publicclassWinFormsTest:Indicator{protectedoverridevoidInitialize(){varresult=System.Windows.Forms.MessageBox.Show("Are you sure you want confirm?","Confirmation",MessageBoxButtons.OKCancel,MessageBoxIcon.Information);if(result==DialogResult.OK){Print("OK");}else{Print("Cancel");}}publicoverridevoidCalculate(intindex){}}}
Bu göstergenin bir örneğini çalıştırdıktan sonra, yukarıda belirttiğiniz metni içeren bir onay kutusu hemen görmelisiniz.
Dosya açma veya kaydetme diyalogları
Dosya açma veya kaydetme diyaloğu, cBot'ların ve göstergelerin yerel olarak depolanan dosyaları göz atmasına ve seçmesine olanak tanımak için kullanılabilir.
Örneklerde, diyaloglarımızla ilgili kodu çalıştırmak için ayrı bir iş parçacığı kullandık. Bu, ana cBot veya gösterge iş parçacığının bir STA iş parçacığı olmaması gerçeğini hesaba katmak için yapıldı. Bu konuyu aşağıdaki bölümde daha ayrıntılı olarak ele alacağız.
Kullanıcı arayüzü için özel bir iş parçacığı kullanma
WinForms'a başvuran kodu çalıştırırken, STA işaretli bir iş parçacığı kullanmanız gerekir, aksi takdirde yürütme sırasında hatalar oluşabilir. Daha fazla bilgi için lütfen resmi belgelere bakın.
Zaten çalışmakta olan bir iş parçacığının ApartmentState özelliğini değiştiremezsiniz. Ana cBot veya gösterge iş parçacığı STA işaretli olmadığı için, WinForms ve WPF için yeni bir STA işaretli iş parçacığı kullanmanız gerekir.
Önceki bölümdeki kod ayrıca thread.Join() yöntemini de çağırır. Bu, kullanıcı arayüzüyle ilgili iş parçacığı serbest bırakılana kadar (örneğin, bir kullanıcı onay diyaloğunda Tamam'a tıklayarak) ana cBot veya gösterge iş parçacığının yürütülmesini engeller.
Bir Windows Formu veya bir WPF öğesi görüntülemek istediğinizde, kodunuzu ayrı bir STA işaretli iş parçacığında çalıştırmanız gerekir.
Yeni bir özel form oluşturma
Şimdiye kadar yerleşik WinForms sınıflarını kullandık. Ancak, özel sınıflar oluşturmak da mümkündür. Bu bölümde, şu anda aktif olan işlem hesabının bakiyesi ve marjı gibi bilgileri gösteren bir form oluşturacağız.
Yeni bir form oluşturmak için Visual Studio'dayken cBot'unuza veya göstergenize sağ tıklayın, Ekle'ye tıklayın ve Kullanıcı Denetimi (Windows Forms) ...'nı seçin.
Visual Studio, projenize eklemek istediğiniz öğenin türünü seçebileceğiniz bir diyalog penceresi açacaktır. Form (Windows Forms)'u seçin (Visual Studio bunu otomatik olarak seçmelidir).
Ardından, form adını Form1.cs'den AccountInfoForm.cs'ye değiştirin. Ekle düğmesine tıklayın.
Projenizin içinde yeni bir form oluşturulacak; IDE, Visual Studio WinForms tasarımcısını görüntüleyecektir. Sonuç olarak, bir araç kutusu aracılığıyla denetimler ekleme dahil tüm özelliklerini kullanabileceksiniz.
Bu örnekte, zaten bir form oluşturduk. Aşağıdaki kodu AccountIntoForm.Designer.cs dosyasına kopyalayıp yapıştırın:
namespaceWinForms_Test{partialclassAccountInfoForm{/// <summary>/// Required designer variable./// </summary>privateSystem.ComponentModel.IContainercomponents=null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protectedoverridevoidDispose(booldisposing){if(disposing&&(components!=null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>privatevoidInitializeComponent(){this.label1=newSystem.Windows.Forms.Label();this.NumberLabel=newSystem.Windows.Forms.Label();this.BrokerLabel=newSystem.Windows.Forms.Label();this.label3=newSystem.Windows.Forms.Label();this.CurrencyLabel=newSystem.Windows.Forms.Label();this.label5=newSystem.Windows.Forms.Label();this.BalanceLabel=newSystem.Windows.Forms.Label();this.label7=newSystem.Windows.Forms.Label();this.EquityLabel=newSystem.Windows.Forms.Label();this.label9=newSystem.Windows.Forms.Label();this.PositionsNumberLabel=newSystem.Windows.Forms.Label();this.label11=newSystem.Windows.Forms.Label();this.OrdersNumberLabel=newSystem.Windows.Forms.Label();this.label13=newSystem.Windows.Forms.Label();this.NetProfitLabel=newSystem.Windows.Forms.Label();this.label15=newSystem.Windows.Forms.Label();this.UpdateButton=newSystem.Windows.Forms.Button();this.SuspendLayout();// // label1// this.label1.AutoSize=true;this.label1.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label1.Location=newSystem.Drawing.Point(12,33);this.label1.Name="label1";this.label1.Size=newSystem.Drawing.Size(72,20);this.label1.TabIndex=0;this.label1.Text="Number:";// // NumberLabel// this.NumberLabel.AutoSize=true;this.NumberLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.NumberLabel.Location=newSystem.Drawing.Point(188,33);this.NumberLabel.Name="NumberLabel";this.NumberLabel.Size=newSystem.Drawing.Size(0,20);this.NumberLabel.TabIndex=1;// // BrokerLabel// this.BrokerLabel.AutoSize=true;this.BrokerLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.BrokerLabel.Location=newSystem.Drawing.Point(188,67);this.BrokerLabel.Name="BrokerLabel";this.BrokerLabel.Size=newSystem.Drawing.Size(0,20);this.BrokerLabel.TabIndex=3;// // label3// this.label3.AutoSize=true;this.label3.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label3.Location=newSystem.Drawing.Point(12,67);this.label3.Name="label3";this.label3.Size=newSystem.Drawing.Size(56,20);this.label3.TabIndex=2;this.label3.Text="Broker";// // CurrencyLabel// this.CurrencyLabel.AutoSize=true;this.CurrencyLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.CurrencyLabel.Location=newSystem.Drawing.Point(188,101);this.CurrencyLabel.Name="CurrencyLabel";this.CurrencyLabel.Size=newSystem.Drawing.Size(0,20);this.CurrencyLabel.TabIndex=5;// // label5// this.label5.AutoSize=true;this.label5.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label5.Location=newSystem.Drawing.Point(12,101);this.label5.Name="label5";this.label5.Size=newSystem.Drawing.Size(75,20);this.label5.TabIndex=4;this.label5.Text="Currency";// // BalanceLabel// this.BalanceLabel.AutoSize=true;this.BalanceLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.BalanceLabel.Location=newSystem.Drawing.Point(188,135);this.BalanceLabel.Name="BalanceLabel";this.BalanceLabel.Size=newSystem.Drawing.Size(0,20);this.BalanceLabel.TabIndex=7;// // label7// this.label7.AutoSize=true;this.label7.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label7.Location=newSystem.Drawing.Point(12,135);this.label7.Name="label7";this.label7.Size=newSystem.Drawing.Size(63,20);this.label7.TabIndex=6;this.label7.Text="Balance";// // EquityLabel// this.EquityLabel.AutoSize=true;this.EquityLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.EquityLabel.Location=newSystem.Drawing.Point(188,173);this.EquityLabel.Name="EquityLabel";this.EquityLabel.Size=newSystem.Drawing.Size(0,20);this.EquityLabel.TabIndex=9;// // label9// this.label9.AutoSize=true;this.label9.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label9.Location=newSystem.Drawing.Point(12,173);this.label9.Name="label9";this.label9.Size=newSystem.Drawing.Size(54,20);this.label9.TabIndex=8;this.label9.Text="Equity";// // PositionsNumberLabel// this.PositionsNumberLabel.AutoSize=true;this.PositionsNumberLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.PositionsNumberLabel.Location=newSystem.Drawing.Point(188,210);this.PositionsNumberLabel.Name="PositionsNumberLabel";this.PositionsNumberLabel.Size=newSystem.Drawing.Size(0,20);this.PositionsNumberLabel.TabIndex=11;// // label11// this.label11.AutoSize=true;this.label11.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label11.Location=newSystem.Drawing.Point(12,210);this.label11.Name="label11";this.label11.Size=newSystem.Drawing.Size(85,20);this.label11.TabIndex=10;this.label11.Text="Positions #";// // OrdersNumberLabel// this.OrdersNumberLabel.AutoSize=true;this.OrdersNumberLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.OrdersNumberLabel.Location=newSystem.Drawing.Point(188,250);this.OrdersNumberLabel.Name="OrdersNumberLabel";this.OrdersNumberLabel.Size=newSystem.Drawing.Size(0,20);this.OrdersNumberLabel.TabIndex=13;// // label13// this.label13.AutoSize=true;this.label13.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label13.Location=newSystem.Drawing.Point(12,250);this.label13.Name="label13";this.label13.Size=newSystem.Drawing.Size(69,20);this.label13.TabIndex=12;this.label13.Text="Orders #";// // NetProfitLabel// this.NetProfitLabel.AutoSize=true;this.NetProfitLabel.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.NetProfitLabel.Location=newSystem.Drawing.Point(188,285);this.NetProfitLabel.Name="NetProfitLabel";this.NetProfitLabel.Size=newSystem.Drawing.Size(0,20);this.NetProfitLabel.TabIndex=15;// // label15// this.label15.AutoSize=true;this.label15.Font=newSystem.Drawing.Font("Segoe UI Variable Display",11.25F,System.Drawing.FontStyle.Bold,System.Drawing.GraphicsUnit.Point);this.label15.Location=newSystem.Drawing.Point(12,285);this.label15.Name="label15";this.label15.Size=newSystem.Drawing.Size(79,20);this.label15.TabIndex=14;this.label15.Text="Net Profit";// // UpdateButton// this.UpdateButton.Location=newSystem.Drawing.Point(273,340);this.UpdateButton.Name="UpdateButton";this.UpdateButton.Size=newSystem.Drawing.Size(75,23);this.UpdateButton.TabIndex=16;this.UpdateButton.Text="Update";this.UpdateButton.UseVisualStyleBackColor=true;this.UpdateButton.Click+=newSystem.EventHandler(this.UpdateButton_Click);// // AccountInfoForm// this.AutoScaleDimensions=newSystem.Drawing.SizeF(7F,15F);this.AutoScaleMode=System.Windows.Forms.AutoScaleMode.Font;this.ClientSize=newSystem.Drawing.Size(360,375);this.Controls.Add(this.UpdateButton);this.Controls.Add(this.NetProfitLabel);this.Controls.Add(this.label15);this.Controls.Add(this.OrdersNumberLabel);this.Controls.Add(this.label13);this.Controls.Add(this.PositionsNumberLabel);this.Controls.Add(this.label11);this.Controls.Add(this.EquityLabel);this.Controls.Add(this.label9);this.Controls.Add(this.BalanceLabel);this.Controls.Add(this.label7);this.Controls.Add(this.CurrencyLabel);this.Controls.Add(this.label5);this.Controls.Add(this.BrokerLabel);this.Controls.Add(this.label3);this.Controls.Add(this.NumberLabel);this.Controls.Add(this.label1);this.Name="AccountInfoForm";this.Text="Account Info";this.Load+=newSystem.EventHandler(this.AccountInfoForm_Load);this.ResumeLayout(false);this.PerformLayout();}#endregionprivateSystem.Windows.Forms.Labellabel1;privateSystem.Windows.Forms.LabelNumberLabel;privateSystem.Windows.Forms.LabelBrokerLabel;privateSystem.Windows.Forms.Labellabel3;privateSystem.Windows.Forms.LabelCurrencyLabel;privateSystem.Windows.Forms.Labellabel5;privateSystem.Windows.Forms.LabelBalanceLabel;privateSystem.Windows.Forms.Labellabel7;privateSystem.Windows.Forms.LabelEquityLabel;privateSystem.Windows.Forms.Labellabel9;privateSystem.Windows.Forms.LabelPositionsNumberLabel;privateSystem.Windows.Forms.Labellabel11;privateSystem.Windows.Forms.LabelOrdersNumberLabel;privateSystem.Windows.Forms.Labellabel13;privateSystem.Windows.Forms.LabelNetProfitLabel;privateSystem.Windows.Forms.Labellabel15;privateSystem.Windows.Forms.ButtonUpdateButton;}}
Yukarıdaki kod WinForms tasarımcısı tarafından oluşturulmuştur. Şimdi yeni form için arka uç kodunu yazacağız. Bunu yapmak için forma sağ tıklayın ve Kodu Görüntüle'yi seçin.
Yeni bir form eklediğinizde, göstergenizin veya cBot'unuzun ad alanını (cAlgo) otomatik olarak kullanacaktır. Hataları önlemek için, eklediğiniz formun ad alanını değiştirin ve ardından göstergenizin veya cBot kaynak kod dosyanıza ekleyin. Bizim durumumuzda, WinForms_Test ad alanı atamasıdır.
Göstergeyi oluşturduktan ve bir örnek oluşturduktan sonra, aşağıdaki formun göründüğünü görmelisiniz.
API üyelerine kullanıcı arayüzüne özel bir iş parçacığından erişin
Daha önce açıkladığımız gibi, WinForm'larınızı çalıştırmak için ayrı, özel bir iş parçacığı kullanmanız gerekir. Yalnızca bu iş parçacığında çalışan kod, form denetimlerine ve özelliklerine erişebilecektir.
Aynı durum tüm algoritmik API üyeleri için de geçerlidir. API iş parçacığı açısından güvenli değildir, bu nedenle Form iş parçacığından API üyelerine erişemezsiniz. Bunun yerine, göstergenizin veya cBot kodunuzdaki BeginInvokeOnMainThread() yöntemini kullanarak bu görevi göndermeniz gerekir.
Bu, göstergeniz veya cBot'unuz ile bir WinForm arasında veri alışverişi yapmak isterseniz sorunlara yol açabilir. Bu sorunu çözmek için, cBot'unuz veya göstergeniz ile Form iş parçacıkları arasındaki etkileşimleri yönetmek üzere bir proxy sınıfı oluşturabilirsiniz.