Please Help, I'm a complete noob. However, i'm working with some complicated API.
I have external class:
namespace IB_CSharp_RealTime_WinForms_CS
{
//! [ewrapperimpl]
public class EWrapperImpl : EWrapper
{
...
//! [historicaldata]
public virtual void historicalData(int reqId, string date, double open, double high, double low, double close, int volume, int count, double WAP, bool hasGaps)
{
Console.WriteLine("HistoricalData. "+reqId+" - Date: "+date+", Open: "+open+", High: "+high+", Low: "+low+", Close: "+close+", Volume: "+volume+", Count: "+count+", WAP: "+WAP+", HasGaps: "+hasGaps);
}
...
And I have a Form
namespace IB_CSharp_RealTime_WinForms_CS
{
public partial class Form1 : Form
{
...
How can I pass "double high" from my external class to my Form?
Thank you in advance!
My full code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading; // Add this for multi-threading support
using IBApi; // Add this for IB API Support
namespace IB_CSharp_RealTime_WinForms_CS
{
public partial class Form1 : Form
{
// This delegate enables asynchronous calls for setting
// the text property on a ListBox control.
delegate void SetTextCallback(string text);
public void AddListBoxItem(string text)
{
// See if a new invocation is required form a different thread
if (this.lbData.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(AddListBoxItem);
this.Invoke(d, new object[] { text });
}
else
{
// Add the text string to the list box
this.lbData.Items.Add(text);
}
}
// Create the ibClient object to represent the connection
// This will be used throughout the form
IB_CSharp_RealTime_WinForms_CS.EWrapperImpl ibClient;
private string tickerId;
public Form1()
{
InitializeComponent();
// Instantiate the ibClient
ibClient = new IB_CSharp_RealTime_WinForms_CS.EWrapperImpl();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnConnect_Click(object sender, EventArgs e)
{
ibClient.ClientSocket.eConnect("", 7496, 0);
var reader = new EReader(ibClient.ClientSocket, ibClient.Signal);
reader.Start();
new Thread(() => {
while (ibClient.ClientSocket.IsConnected())
{
ibClient.Signal.waitForSignal();
reader.processMsgs();
}
})
{ IsBackground = true }.Start();
while (ibClient.NextOrderId <= 0) { }
// Set up the form object in the EWrapper
ibClient.myform = (Form1)Application.OpenForms[0];
}
private void btnDisconnect_Click(object sender, EventArgs e)
{
// Disconnect from interactive Brokers
ibClient.ClientSocket.eDisconnect();
}
private void btnStart_Click(object sender, EventArgs e)
{
// Create a new contract to specify the security we are searching for
IBApi.Contract contract = new IBApi.Contract();
// Create a new TagValueList object (for API version 9.71 and later)
List < IBApi.TagValue > mktDataOptions = new List<IBApi.TagValue>();
// Set the underlying stock symbol from the tbSymbol text box
contract.Symbol = tbSymbol.Text;
// Set the Security type to STK for a Stock
contract.SecType = "STK";
// Use "SMART" as the general exchange
contract.Exchange = "SMART";
// Set the primary exchange (sometimes called Listing exchange)
// Use either NYSE or ISLAND
contract.PrimaryExch = "ISLAND";
// Set the currency to USD
contract.Currency = "USD";
// Kick off the subscription for real-time data (add the mktDataOptions list for API v9.71)
ibClient.ClientSocket.reqMktData(1, contract, "", false, mktDataOptions);
// For API v9.72 and higher, add one more parameter for regulatory snapshot
// ibClient.ClientSocket.reqMktData(1, contract, "", false, false, mktDataOptions);
} // end btnStart_Click
private void btnStop_Click(object sender, EventArgs e)
{
// Make the call to cancel the market data subscription
ibClient.ClientSocket.cancelMktData(1);
}
}
}
What I want is TextBox1.Text to show the value of "high". Basically if I can learn on how to pass that value I can use it to pass all other values.
Related
I have setup an Class that holds names/Numbers/ect, and created a List of objects to hold them. I want to display them on a second Form in a ListView. Right now I am using a getter like...
public List<Employee> GetEmpList(){
return EmployeeList;
}
Then in the second Form's constructor I am using the Form1.GetEmpList() like...
DisplayForm{
InitializeComponent();
LoadEmployees(EmployeeAddition.GetList());
}
I am getting and error saying "an object reference is required for the nonstatic field". The method I am calling is non-static, and returns a reference to the List in the Form1 class. I have even tried to just make the List public and calling using Form1.List but it still gives me the same error.
Is there a way to pass a List between Form classes or is it impossible?
EDIT: Poeple said that more information was needed. I didn't want to copy paste all the code here, but I am going to put a good chunk just because I am new and not quite sure what is relevant and what is not. (I am taking a class, but remotely, and my teacher is...well a remote teacher, useless. She actually told me to ask here)
I guess I am missing how to instatize a method, I thought that when the object was created from the class the method became part of the object. The Method is part for the Form1 (Renamed but thats what it is) class/object. I will dumb the code under here, I don't know if that is frowned upon; if so I am sorry.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace EmplyeeList
{
public partial class EmployeeDisplay : Form
{
public EmployeeDisplay()
{
InitializeComponent();
LoadEmployees(EmployeeAddition.GetList());
}
private void LoadEmployees(IList<CorpEmployee> emp)
{
foreach (CorpEmployee ce in emp)
{
ListViewItem lvi = new ListViewItem();
lvi.SubItems.Add(ce.Name);
lvi.SubItems.Add(ce.Address);
lvi.SubItems.Add(ce.PhoneNumber);
lvi.SubItems.Add(ce.ServiceArea);
lvi.SubItems.Add(ce.EmplNumber.ToString());
lvi.SubItems.Add(ce.RoomNumber.ToString());
lvi.SubItems.Add(ce.PhoneExt.ToString());
lvi.SubItems.Add(ce.email);
displayListView.Items.Add(lvi);
}
}
private void closeButton_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
This is the first Form class to load...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace EmplyeeList
{
public class EmployeeAddition : Form
{
//Create a list to hold CorpEmployee objects.
private List<CorpEmployee> CorpEmplList = new List<CorpEmployee>();
public EmployeeAddition()
{
InitializeComponent();
}
private void saveButton_Click(object sender, EventArgs e)
{
int testingNum; //Used for output in parsing numbers
//If statments are used to make sure ints are ints, and nothing is blank.
if (Int32.TryParse(employeeNumTextBox.Text, out testingNum) || ! (employeeNumTextBox.Text == ""))
{
if (Int32.TryParse(roomNumTextBox.Text, out testingNum) || !(roomNumTextBox.Text == ""))
{
if (Int32.TryParse(phoneExtTextBox.Text, out testingNum) || !(phoneExtTextBox.Text == ""))
{
if (!(nameTextBox.Text == "") || !(addressTextBox.Text == "") || !(titleTextBox.Text == "") || !(phoneNumberTextBox.Text == "") ||
!(serviceAreaTextBox.Text == "") || !(emailTextBox.Text == ""))
{
//If all fields are filled in right then we add the object to the List
CorpEmplList.Add(CreateCorpEmployee(nameTextBox.Text, addressTextBox.Text, titleTextBox.Text,
phoneNumberTextBox.Text, serviceAreaTextBox.Text,
Convert.ToInt32(employeeNumTextBox.Text), Convert.ToInt32(roomNumTextBox.Text),
Convert.ToInt32(phoneExtTextBox.Text), emailTextBox.Text));
//Let the user know it was added
MessageBox.Show("Employee was added!");
//Clear fields
ClearAllFields();
}
else
{
MessageBox.Show("All fields must be filled in.");
}
}
else
{
MessageBox.Show("Phone Ext.# should be a number");
}
}
else
{
MessageBox.Show("Check your Room# and try again.");
}
}
else
{
MessageBox.Show("Employee Number Should be a number.");
}
}
//This takes in all the employee fields and returns a contructed object
private CorpEmployee CreateCorpEmployee(String name, String address, String title, String phoneNumber,
String serviceArea, int emplNumber, int roomNumber, int phoneExt, String email)
{
CorpEmployee corpEmpObject = new CorpEmployee(name, address, title, phoneNumber, serviceArea, emplNumber, roomNumber, phoneExt, email);
return corpEmpObject;
}
//This just clears all the fiels
private void ClearAllFields()
{
nameTextBox.Text = "";
addressTextBox.Text = "";
titleTextBox.Text = "";
phoneNumberTextBox.Text = "";
serviceAreaTextBox.Text = "";
employeeNumTextBox.Text = "";
roomNumTextBox.Text = "";
phoneExtTextBox.Text = "";
emailTextBox.Text = "";
}
//This returns the List of CorpEmployees
public List<CorpEmployee> GetList()
{
return CorpEmplList;
}
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void clearButton_Click(object sender, EventArgs e)
{
ClearAllFields();
}
private void showButton_Click(object sender, EventArgs e)
{
EmployeeDisplay ed = new EmployeeDisplay();
ed.Show();
}
}
}
After relooking at the code I think I might see what you are saying about calling it from a static class, not an object. Is there a way to find the name of the Object that the Compiler creates from the first Form?
The first problem you are having is you are treating the GetEmpList() function as an static method. It is not static and probably shouldn't be static. That is why people are saying you need to create an instance of it. However, looking at what you are asking the way you are going about this is probably flawed in a more fundamental way that just creating a new version of the form will solve. The problem is you want to pass model data between forms. Without more information it is really hard to tell how you want this all to go together. However you probably already have an instance of the EmployeeAddition form and don't need to create another instance inside the constructor of your DisplayForm. Instead what you should do is make the LoadEmployees method public and pass the results of GetEmpList() into that.
So your structure would be more like
public class EmployeeAddition : Form {
...
public List<Employee> GetEmpList(){
return EmployeeList;
}
...
public void ShowDisplayForm(){
var displayForm = new DisplayForm();
displayForm.LoadEmployees(GetEmpList());
displayForm.Show();
}
...
}
Of course this structure may be slightly off as I'm guessing at which form will own which form but this is closer to what you want.
try use "new"
DisplayForm{
InitializeComponent();
EmployeeAddition = new EmployeeAdditionClass();
LoadEmployees(EmployeeAddition.GetList());
}
I am trying to learn classes, meaning writing codes outside of the windows form and calling that code in the form. I created a basic calculation in the form and it works. The problem is, I want to know how I can move the entire calculation into a class and call it into the form on load or when a control is click. It does not work!
Here is my local or form version which works:
Please note that the form will load with the first calculation because the Radiobutton is checked on load.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Calculations
{
public partial class Calculations : Form
{
public Calculations()
{
InitializeComponent();
}
public decimal SalesTax = 0.065M;
public decimal AppliedTax;
public decimal Price;
public decimal SubTotal;
public decimal GrandTotal;
public object Calc()
{
Int32 GetQuantity = Convert.ToInt32(txtQuantity.Text);
SubTotal = (Price * GetQuantity);
AppliedTax = (SubTotal * SalesTax);
GrandTotal = (SubTotal + AppliedTax);
if (radRed.Checked == true)
{
Price = 100;
}
else if (radBlue.Checked == true)
{
Price = 200;
}
else if (radGreen.Checked == true)
{
Price = 300;
}
lblPrice.Text = GrandTotal.ToString("c");
return GrandTotal;
}
private void Calculations_Load(object sender, EventArgs e)
{
txtQuantity.Text = "10";
radRed.Checked = true;
Calc();
}
private void radRed_CheckedChanged(object sender, EventArgs e)
{
Calc();
}
private void radBlue_CheckedChanged(object sender, EventArgs e)
{
Calc();
}
private void radGreen_CheckedChanged(object sender, EventArgs e)
{
Calc();
}
private void btnCalculate_Click(object sender, EventArgs e)
{
Calc();
}
}
}
And here is my attempt to place all of this in a class:
It works but not on load, you have to check another radiobutton first
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculations
{
class ClsCalc
{
class ClsRef
{
public static Calculations FormCtrls
{
get
{
return Calculations.ActiveForm as Calculations;
}
}
}
public static decimal SalesTax = 0.065M;
public static decimal AppliedTax;
public static decimal Price;
public static decimal SubTotal;
public static decimal GrandTotal;
public static object Calc()
{
Int32 GetQuantity = Convert.ToInt32(ClsRef.FormCtrls.txtQuantity.Text);
SubTotal = (Price * GetQuantity);
AppliedTax = (SubTotal * SalesTax);
GrandTotal = (SubTotal + AppliedTax);
if (ClsRef.FormCtrls.radRed.Checked == true)
{
Price = 100;
}
else if (ClsRef.FormCtrls.radBlue.Checked == true)
{
Price = 200;
}
else if (ClsRef.FormCtrls.radGreen.Checked == true)
{
Price = 300;
}
ClsRef.FormCtrls.lblPrice.Text = GrandTotal.ToString("c");
return GrandTotal;
}
}
}
Finally I called it in the form Load event:
ClsCalc.Calc();
Please note this is not a real project just a way to learn, well for me that is.
Thank you!
Your calculation method is almost entirely involving interactions with UI elements. You gather a bunch of information from a textbox and various checkboxes, and then have just three lines of actual calculations, and then you display the results.
UI interaction shouldn't be moved outside of the form. You shouldn't expose the internal controls of a form publicly; they should only ever be accessed from within their parent form (or user control, if that's the case).
A common pattern that you'll see when performing some form submit operation is to gather information from input controls, do some calculations on the data, and then display the results on the form. Both the gathering information and displaying results should stay within the form, the only thing that you should (potentially) move outside of the form's definition is the calculations. In this case that's such a small amount of work there just isn't a compelling reason to do that.
I'm creating a checkout system for a supermarket. It consists of a checkout, server and MIS program an operates WCF services between them. The problem I have is that the checkout program, which is a windows form, does a few neccessaries in it's application_load method and then just quits.
Here's the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CheckoutLibrary;
using Checkout.ServerLibraryService;
using Checkout.MarketService;
namespace Checkout
{
public partial class theForm : Form
{
private static int checkoutID = 3;
private Product[] allProducts;
public theForm()
{
InitializeComponent();
}
private void theForm_Load(object sender, EventArgs e)
{
// First cache all products
SupermarketServiceSoapClient marketService = new SupermarketServiceSoapClient();
allProducts = marketService.GetAllProducts();
// Load the service provided by the server
ServiceClient serverService = new ServiceClient();
// Load the event handlers for the bar code scanner
BarcodeScanner scanner = new BarcodeScanner();
scanner.ItemScanned += new BarcodeScanner.ItemScannedHandler(scanner_ItemScanned);
scanner.AllItemsScanned += new BarcodeScanner.AllItemsScannedHandler(scanner_AllItemsScanned);
scanner.Start(checkoutID);
}
void scanner_AllItemsScanned(EventArgs args)
{
throw new NotImplementedException();
}
void scanner_ItemScanned(ScanEventArgs args)
{
itemTextBox.Text = "Scanned " + GetItemName(args.Barcode);
}
private void scanItemButton_Click(object sender, EventArgs e)
{
scanner_ItemScanned(new ScanEventArgs(GetRandBarcode()));
}
// A barcode -> product name look up method
public string GetItemName(int barcode)
{
return allProducts[barcode].Description + " # " + allProducts[barcode].Price;
}
// Method to grab a random barcode for simulation
private int GetRandBarcode()
{
Random rand = new Random();
return rand.Next(0,500);
}
}
}
And program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Checkout
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new theForm());
}
}
}
Thanks for any insight.
In WinForms, if your form_load throws an exception, it quits without displaying anything. Annoying, but I'm guessing that's the problem.
You can try a try/catch, or you can hit CTRL+ALT+E and check the Thrown Column for Common Language Runtime Exceptions to see the error.
UPDATE:
Based on comments, here's a sample way to execute something on another thread.
ThreadStart ts = new ThreadStart(() => {
try {
scanner.Start(checkoutID);
} catch {
// Log error
}
});
Thread t = new Thread(ts);
t.Start();
I am rewriting my last question, just because I am trying to attack the problem from differente angles..
The problem is this. I have a class written in C#, with two public methods, and an eventhandler that triggers everytime any of the methods is completed.
I created this class adapting the code from a Form.
Now, if I reference this class from a Windows Process project written in VB.Net, and I call any of the two methods, the EventHandler will NOT trigger
Could this problem be related to EventHandler's scope or anything like that?
If necessary, I can post code
Thanks
++++++++++++++++++++++++
UPDATE
++++++++++++++++++++++++
Ok.. here is the code. Originally I was calling the methods from a class, but I modified the whole project just to see if the problem had to do with trying to raise the event from the class... So I have this c# webserver listening on port 8080, and upon http request calls ENROLL or IDENTIFY according to URL parameters.
Just to clarify a bit. This is a webserver that will run in a computer which has a USB fingerprint scanner connected. Then, the web application will do an http request to that computer in order to execute an IDENTIFICATION or ENROLLMENT, actions which are programmed inside the webserver, manipulating the methods included in the scanner's driver which I got with the SDK.
In have a C# demo project which came with the driver's SDK, a simple form with buttons calling ENROLL or IDENTIFY methods from the CLICK event. After the CLICK event is finished (inside of which is executed the ENROLL or IDENTIFY methods) then the Event is triggered and the EventHandler executes.
So now I have all the code in the same project, but it is still behaving the same way... it goes into the ENROLL method which executes the StartEnroll method from the WisSensorNLibLib class, but the event is not triggered nor captured by the class' custom Event Handler...
Maybe I am misplacing the definitions or the instantiations... I don't know. But the event is not triggered...
So here is the code... (and below I will paste the original Demo program code, so maybe by comparison someone can find out what the problem could be)
namespace WinServer
{
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
//************************************
//This is the class that belongs to the Fingerprint Scanner
//************************************
using WisSensorNLibLib;
class WinServer
{
private TcpListener myListener ;
private int port = 8080 ; // Select any free port you wish
private Int16 id;
private string indx;
//************************************
//Create instance of WisSensorN
//************************************
WisSensorN WisObj = new WisSensorN();
private String mod;
private Int32 Rows;
public WinServer()
{
try
{
myListener = new TcpListener(IPAddress.Any, port) ;
myListener.Start();
Thread th = new Thread(new ThreadStart(StartListen));
th.Start() ;
}
catch(Exception e)
{
Console.WriteLine("An Exception Occurred while Listening :" +e.ToString());
}
}
public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket mySocket)
{
//************************************
//Code not related to understand specific problem was removed
//************************************
}
public void SendToBrowser(String sData, ref Socket mySocket)
{
//************************************
//Code not related to understand specific problem was removed
//************************************
}
public void SendToBrowser(Byte[] bSendData, ref Socket mySocket)
{
//************************************
//Code not related to understand specific problem was removed
//************************************
}
// Application Starts Here..
public static void Main()
{
WinServer MWS = new WinServer();
}
public void StartListen()
{
//Call ENROLL method
Enroll();
mySocket.Close();
}
//**********************************
//EVENT CAPTURE
//**********************************
public void WisObj_DataEvent(WisSensorNLibLib.DATA data, string str)
{
switch (data)
{
//ENROLL
case DATA.DATA_ENROLL:
try
{
Console.WriteLine("success");
}
catch (Exception ee)
{
Console.WriteLine(ee.Message);
}
break;
//IDENTIFY
case DATA.DATA_IDENTIFY_CAPTURE:
try
{
Console.WriteLine("Success");
}
catch (Exception ee)
{
Console.WriteLine(ee.Message);
}
break;
}
}
//**********************************
//ENROLL
//After this method ends, WisObj_DataEvent should capture the event
//**********************************
public void Enroll()
{
try
{
WisObj.Open();
WisObj.DataEvent += new _IWisSensorNEvents_DataEventEventHandler(WisObj_DataEvent);
WisObj.StartEnroll();
}
catch
{
Console.WriteLine(ee.Message);
}
}
//**********************************
//IDENTIFY
//After this method ends, WisObj_DataEvent should capture the event
//**********************************
public void Identify()
{
try
{
WisObj.Open();
WisObj.DataEvent += new _IWisSensorNEvents_DataEventEventHandler(WisObj_DataEvent);
WisObj.IdentifyCapture();
}
catch
{
Console.WriteLine(ee.Message);
}
}
public void WisClose()
{
WisObj.Close();
}
}
}
Original Demo program code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using WisSensorNLibLib;
namespace OR200N_Demo
{
public partial class Form1 : Form
{
private const int MaxUser = 10;
WisSensorN WisObj = new WisSensorN();
string[] DB = new string[MaxUser];
int nEnrolled = 0;
string indx;
string msg;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
MessageBox.Show("Please make sure the scanner is plugged!!");
WisObj.Open();
WisObj.DataEvent += new _IWisSensorNEvents_DataEventEventHandler(WisObj_DataEvent);
WisObj.SetDisplay((int)FingerPic.Handle);
}
private delegate void CompleteHandler(string bir);
private void Complete(string str)
{
Status.Text = str;
}
private void WisObj_DataEvent(WisSensorNLibLib.DATA data, string str)
{
switch (data)
{
case DATA.DATA_ENROLL:
indx = nEnrolled.ToString();
msg = "User #" + indx + " is enrolled successfully!!";
this.Invoke(new CompleteHandler(Complete), new object[] { msg });
DB[nEnrolled] = string.Copy(str);
nEnrolled++;
break;
case DATA.DATA_IDENTIFY_CAPTURE:
int nMatched;
nMatched = WisObj.Identify(str, DB);
if (nMatched < 0)
{
msg = "No valid finger matched!!";
this.Invoke(new CompleteHandler(Complete), new object[] { msg });
}
else
{
indx = nMatched.ToString();
msg = "User #" + indx + " is matched!!";
this.Invoke(new CompleteHandler(Complete), new object[] { msg });
}
break;
case DATA.DATA_VERIFY_CAPTURE:
break;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
WisObj.Close();
}
private void Enroll_Click(object sender, EventArgs e)
{
if (nEnrolled >= MaxUser)
{
MessageBox.Show("Exceed maximum enrolled number (10)!!");
}
else
{
Status.Text = "Please put your finger on the scanner!!";
WisObj.StartEnroll();
}
}
private void Identify_Click(object sender, EventArgs e)
{
Status.Text = "Please put your finger on the scanner!!";
WisObj.IdentifyCapture();
}
}
}
Firstly, it is event, not event handler, which is being raised.
Event handler is a method that subsribes to a given event.
Secondly, scope only governs member visibility at compile time and does not affect event subscriptions. If event is visible, it works.
From what you posted, one may only conclude that:
You may not subscribe to event in VB .NET code or may handle it incorrectly;
When called from VB .NET code, these methods may act differently (different parameters being passed? exeptions thrown?) and may not raise the event.
So far, this is all I can say until I see the code.
Can you trim it down to simplest reproducible case?
First post, long time reader.
I'm currently learning C# with "Head First C#" (I'm up to Encapsulation and Get/Set properties)
I'm writing a small program to work with pictures for a friend, I'm just wondering if I'm heading along the right lines with my PictureController class? My main problem is that I am setting a lot of form items with this class, and it feels unnatured to keep referencing form items from within the class, I'm pasting my code below, if you could let me know if I'm doing anything wrong then I'd be most grateful :)
Many thanks!
PictureController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
namespace PictureController
{
class PictureController
{
private int arrayPosition = 0;
private int numFiles = 0;
private string[,] arrayPictures;
public PictureBox myPictureBox;
public RadioButton myCopyButton;
public RadioButton myDeleteButton;
public TextBox mySource;
public ComboBox myDestinations;
private FolderBrowserDialog sourceFolder;
private FolderBrowserDialog destFolder;
public void InitialisePicture()
{
if (arrayPictures != null && arrayPictures.Length > 0)
{
myPictureBox.ImageLocation = arrayPictures[arrayPosition, 0];
}
else
{
MessageBox.Show("The folder you have selected contains no pictures...");
myPictureBox.ImageLocation = null;
}
}
public void NavigatePicture(int direction)
{
if (arrayPosition + direction >= 0 && arrayPosition + direction < numFiles)
{
arrayPosition += direction;
myPictureBox.ImageLocation = arrayPictures[arrayPosition, 0];
myCopyButton.Checked = Convert.ToBoolean(arrayPictures[arrayPosition, 1]);
myDeleteButton.Checked = Convert.ToBoolean(arrayPictures[arrayPosition, 2]);
}
}
public void UpdateActions(bool copyChecked, bool deleteChecked)
{
if (arrayPictures != null)
{
arrayPictures[arrayPosition, 1] = copyChecked.ToString();
arrayPictures[arrayPosition, 2] = deleteChecked.ToString();
}
}
public void GetFiles()
{
sourceFolder = new FolderBrowserDialog();
sourceFolder.ShowDialog();
if (sourceFolder.SelectedPath != "")
{
string[] arrayTempFiles = Directory.GetFiles(sourceFolder.SelectedPath,"*.jpg");
numFiles = arrayTempFiles.Length;
arrayPictures = new string[arrayTempFiles.Length,3];
for (int i = 0; i < arrayTempFiles.Length; i++)
{
arrayPictures[i, 0] = arrayTempFiles[i];
arrayPictures[i, 1] = "false";
arrayPictures[i, 2] = "false";
}
mySource.Text = sourceFolder.SelectedPath;
InitialisePicture();
}
}
public void AddDestinationFolder()
{
destFolder = new FolderBrowserDialog();
destFolder.ShowDialog();
if (destFolder.SelectedPath != "")
{
myDestinations.Items.Add(destFolder.SelectedPath);
}
}
}
}
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace PictureController
{
public partial class Form1 : Form
{
PictureController PicControl;
public Form1()
{
InitializeComponent();
PicControl = new PictureController() { myPictureBox = pbPhoto, myCopyButton = rbMove, myDeleteButton = rbDelete, mySource = tbSource, myDestinations = cbDestination };
}
private void btnPrev_Click(object sender, EventArgs e)
{
PicControl.NavigatePicture(-1);
}
private void btnNext_Click(object sender, EventArgs e)
{
PicControl.NavigatePicture(1);
}
private void rbMove_CheckedChanged(object sender, EventArgs e)
{
if (rbMove.Checked || rbDelete.Checked)
{
PicControl.UpdateActions(rbMove.Checked, rbDelete.Checked);
}
}
private void rbDelete_CheckedChanged(object sender, EventArgs e)
{
if (rbMove.Checked || rbDelete.Checked)
{
PicControl.UpdateActions(rbMove.Checked, rbDelete.Checked);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.A:
PicControl.NavigatePicture(-1);
break;
case Keys.D:
PicControl.NavigatePicture(1);
break;
case Keys.W:
rbMove.Checked = true;
break;
case Keys.S:
rbDelete.Checked = true;
break;
}
}
private void btnGetFiles_Click(object sender, EventArgs e)
{
PicControl.GetFiles();
}
private void btnProcess_Click(object sender, EventArgs e)
{
}
private void btnAddDest_Click(object sender, EventArgs e)
{
PicControl.AddDestinationFolder();
}
}
}
I don't see the reason to use Controls in your PictureController class. You should only use non-forms datatypes there and handle the interaction in your Form, offering events and methods from your PictureController class to react and act on it.
It's a good start in my opinion.
Hard to tell if you're doing something "wrong" because it depends what you think is right, every programmer has his/her own style and best practice set and as long as the code is working and efficient it's "right". There are many roads leading to Rome. :)
Anyway if you ask for personal opinion or advice, I would make two major changes in logic:
Have the Controller be a static class (Singleton if you prefer)
Don't pass or use the form controls directly. Instead pass the instance of your form to the static class in some Initialize method, then use that instance and call public method that is working with the controls directly.
Example for the second change:
public static void NavigatePicture(int direction)
{
if (arrayPosition + direction >= 0 && arrayPosition + direction < numFiles)
{
arrayPosition += direction;
_formInstance.SetPictureLocation(arrayPictures[arrayPosition, 0]);
_formInstance.SetCopyStatus(Convert.ToBoolean(arrayPictures[arrayPosition, 1]));
_formInstance.SetDeleteStatus(Convert.ToBoolean(arrayPictures[arrayPosition, 2]));
}
}
//...and in the form:
public SetPictureLocation(sLocation)
{
myPictureBox.ImageLocation = sLocation;
}
What is the point of having the controller, just encapsulate the extra logic out of the form? Do you need your controller to be testable? Do you want to use an abstract model of your business logic? If you answer yes to last 2 questions you might want to google:
a. MVC pattern
b. MVP pattern
Everything is wrong.
Controller (if it is a controller of the form/window) should know about form while in your sample - form know about controller.
Controller should know how to build data / and handle some form events when in your sample controller have references to pictureBox'es etc.
And there are no need to "extract" controller from the control code, while doesn't established what the "data/model" of the control is (and not framed with the type).
It's not clear what is the data there: path or image collection.