windows.forms usercontrol, event and delegate

M

MKMOBILE

Hi

I want to prepare a customcontrol consist of a label, one property
LabelText- a text for label control and a window Form. When click on
the label the window form should appear and display a TextBox to edit
a a text label.

I think that a setting custom property LabelText should fire a event
TextChanged, the Form if displayed should subscribe the event
TextChanged and run some function if event fired.

the problem is how to describe event which not have a instance of real
object but only a usercontrol definition. Real object is created when
add the usercontrol to a new form a then you give some name to it.
Then it's quite easy to describe event.
 
J

Jeroen van Langen

?>Hi

Hi
I want to prepare a customcontrol consist of a label, one property
LabelText- a text for label control and a window Form. When click on
the label the window form should appear and display a TextBox to edit
a a text label.

So you have a form with for example a custom label. If the user click the
label a window should appear. The user can change the label content with the
textbox and hits a ok button to submit the change back to the label. Also
should the label fire an event when the text has changed.
I think that a setting custom property LabelText should fire a event
TextChanged, the Form if displayed should subscribe the event
TextChanged and run some function if event fired.
the problem is how to describe event which not have a instance of real
object but only a usercontrol definition. Real object is created when
add the usercontrol to a new form a then you give some name to it.
Then it's quite easy to describe event.

I maybe don't understand you completely, so if I'm wrong ignore this post :)

I would create a class derived from Label to maintain the Label's behavior.
I add some properties for the information shown on the edit window

On the edit form I've added a labelDescription (to give information what the
user should enter)
A TextBox for the user to enter the information.
2 buttons:
- Ok button (DialogResult = Ok)
- Cancel button (DialogResult = Cancel)


The edit form class looks like this:
---------------------------------------------------------------
public partial class FormEdit : Form
{
public FormEdit()
{
InitializeComponent();
}

// the textbox text property wrapper
public string EditText
{
get
{
return textBox1.Text;
}
set
{
textBox1.Text = value;
}
}

// the label text property wrapper
public string Description
{
get
{
return labelDescription.Text;
}
set
{
labelDescription.Text = value;
}
}
}
---------------------------------------------------------------

And the EditLabel class should look like:

---------------------------------------------------------------
public class EditLabel : Label
{
// The description show above the TextBox in the EditForm
[Category("Edit")]
public string EditDescription { get; set; }

// The caption of the Edit form
[Category("Edit")]
public string EditCaption { get; set; }

public EditLabel()
{
// My class likes to know when the label is clicked, so i register
the click_eventhandler of the base class Label.
this.Click += new EventHandler(EditLabel_Click);
}

// my click_eventhandler
void EditLabel_Click(object sender, EventArgs e)
{
// Create an instance of the edit form
FormEdit editForm = new FormEdit();

// set the Description of the edit form
editForm.Description = this.EditDescription;

// set the caption of the edit form
editForm.Text = this.EditCaption;

// set the labels text to the textbox text property wrapper.
editForm.EditText = Text;

// show the dialog and capture the dialog result
DialogResult result = editForm.ShowDialog();

// if the user cancels or closes the edit, return from the method
if (result != DialogResult.OK)
return;

// when the text in the edit form is different than the current
label's Text property
if (editForm.EditText != this.Text)
{
// change the labels text property contents
Text = editForm.EditText;

// if there are any TextChanged eventhandlers registered, fire
them
if (TextChanged != null)
TextChanged(this, EventArgs.Empty);
}
}

// The textchange handler
public event EventHandler TextChanged;
}
---------------------------------------------------------------

The TextChanged eventhandler will only be fired when you change the text in
the editform.


I hope that this is what you're looking for, besides that I enjoyed writing
it :)

Jeroen
 
M

MKMOBILE

The System.Windows.Forms.Label class already has a Text property.  Why
do you need another one?


actually, a custom Label control is only an example. I work on custom
control which is more complicate and the custom Label control is the
way to see the possible solution.
 
M

MKMOBILE

Ok

I will try to explain what actually I try to do...

the idea is to create a user control for automation system like SCADA,
for example a valve control. Valve should have a property [uState] to
read a state from real valve from a PLC controller and a property to
send command to PLC [uCommand]. For this moment we can concentrate
only on a [uStatus] property. Valve control is a graphical
representation of real valve state. If real valve is opened the valve
symbol on the control is green, if valve is closed the valve symbol on
the control is gray, if valve is in fault the valve symbol on the
control is red.

When you click on valve control the valve control faceplate should
appear. This form should be coded inside the usercontrol. The
faceplate make possible to control the valve: OPEN valve, CLOSE valve,
this many other information... On the faceplate we duplicate a valve
control symbol.

My idea is when the usercontrol property [uState] is change, the
colour of the valve symbol in the control change and if the faceplate
is opened the the colour of the valve symbol in the faceplate change.
I want to fire a event when set the property [uState], if the
faceplate is opened it subsribe event and follow the status change.

the user control code: http://img96.imageshack.us/img96/7807/valvecontrol.gif

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ValveControl
{

public partial class ValveUserControl : UserControl
{
private string ValveText = "";
private byte ValveState = 0;

public string uValveText
{
get { return ValveText; }
set
{
ValveText = value;
ValveLabel.Text = value;
}
}
public byte uValveState
{
get
{
return ValveState;
}
set
{
ValveState = value;
this.Refresh(); //

//animate valve color
switch (value)
{
case 0: ValvePicture.Image =
ValveControl.Properties.Resources.ValveGy; break;
case 1: ValvePicture.Image =
ValveControl.Properties.Resources.ValveG; break;
case 2: ValvePicture.Image =
ValveControl.Properties.Resources.ValveR; break;
}

//
if (StatusChanged != null)
{
StatusChanged(this, uValveState);
}
}
}


//delegate
public delegate void MyEventHandler(object sender, byte
Status);
//

//events
[Category("Action")]
[Description("Fires.")]
public event MyEventHandler StatusChanged;
//

public ValveUserControl()
{
InitializeComponent();
}


private void ValvePicture_Click(object sender, EventArgs e)
{
ValveControlForm myForm = new ValveControlForm();
myForm.Show();
myForm.Text = "Valve " + uValveText +" - Control
Faceplate";
}
}
}


the faceplate http://img209.imageshack.us/img209/4643/valvecontrolfaceplate.gif

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 ValveControl
{
public partial class ValveControlForm : Form
{

public ValveControlForm()
{
InitializeComponent();
{
//ValveControl.ValveUserControl valve = new
ValveUserControl();
//valve.StatusChanged += new
ValveUserControl.MyEventHandler(ValveControlForm_StatusChanged);
//valve.uValveState = 1;

// here should be a assign to event
}
}


private void ValveControlForm_StatusChanged(object sender,
byte NewStatus)
{
MessageBox.Show("New status = " + NewStatus.ToString());
}

private void bOpen_Click(object sender, EventArgs e)
{
}
}
}


test appliacation with two instances of the valve control - VALVE1 and
VALVE2 with buttons to change [uState] property of each valve:
http://img713.imageshack.us/img713/838/runtimeapp.gif

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 WindowsFormsApplication1
{
public partial class Runtime : Form
{
public Runtime()
{
InitializeComponent();
}

private void bValve1Gray_Click(object sender, EventArgs e)
{
Valve1.uValveState = 0;
}

private void bValve1Green_Click(object sender, EventArgs e)
{
Valve1.uValveState = 1;
}

private void bValve1Red_Click(object sender, EventArgs e)
{
Valve2.uValveState = 2;
}

private void bValve2Gray_Click(object sender, EventArgs e)
{
Valve2.uValveState = 0;
}

private void bValve2Green_Click(object sender, EventArgs e)
{
Valve2.uValveState = 1;
}

private void bValve2Red_Click(object sender, EventArgs e)
{
Valve2.uValveState = 2;
}

}
}
 
M

MKMOBILE

uState shall be ony to read for the usercontrol. User interaction will
send command to PLC (ie force to open or to close valve) using other
usercontrol property [uCommand]
 
M

MKMOBILE

the problem is in this part - in a form which belongs to usercontrol,

I need assign a event to call ValveControlForm_StatusChanged method
when status changed.

but I don't know how to bind event to object who hasn't instance
representation...


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 ValveControl
{
public partial class ValveControlForm : Form
{

public ValveControlForm()
{
InitializeComponent();
{
// here should be a assign to event

}
}

private void ValveControlForm_StatusChanged(object sender,
byte NewStatus)
{
MessageBox.Show("New status = " + NewStatus.ToString());

//call function to change valve colour
}

private void bOpen_Click(object sender, EventArgs e)
{
}
}

}
 
M

MKMOBILE

Pete I didn't want to describe how the automations systems works but
now I see that I have to... :)))

ok.

so... the main control system is a PLC controller, actually only PLC
can open or close real valve and generally do not need any other
computers to work... but sometimes its very useful to disturb
automatic program in PLC and do some manual operation... then you can
use simple HMI (Human Machine Interface) touchpanel or use a more
complicated SCADA systems (PC based). Then the PLC works like a
gateway between mechanical equipment like valves, motors, pumps....
and the SCADA or HMI. But still all electrical control is located in
PLC.
SCADA system are mainly use to supervisory of the process, you can see
which equipments works good, which fails and so on...

If you want to do some manual control, you have to send information to
the PLC that you want to change a mode of control for some equipment
ex. valve. Then is possible to open/close the valve manually. SCADA
system uses labels which in deed is a reference to memory in PLC, but
its more user friendly to use TAG name ex. "Valve1.Status" instead a
real memory address like "DB10.WORD20" which tells nothing... Tag is
nothing more then a label assign to memory address.

You have to know that distance between PLC and SCADA computer could by
hundred of meters or in some case event hundred of kilometres
(miles)...the communications rate is different some times only
19,2kbps some times 100Mbps... thats why usually it's better to set a
value then call method...especially that PLC not use methods... You
can only read from - or write to PLC memory...

so...
when I want to send a command to PLC to open a Valve usually set a BIT
(or set a BIT in WORD) than PLC notice this and do action to open the
valve.

Present SCADA system are a container for ActiveX or .NET controls. So
it's very useful to prepare a library with typical template control
like valve, motors, pumps. Than you have only to assign a right
properties of control to Tags and your automation system is near to
ready... and what it's important it doesn't matter what SCADA software
use.

in other way you can prepare own SCADA in programming language like
C#, C++, VB.... but then you have to implement a driver to PLC which
is not easy... or what Jeroen ask me - it's use a OPC communication
standard.

Actually in this moment it's not matter do we use the prepared
controls in SCADA or in OPC client applications. At this moment I want
only to manage with the problem how automatic change valve status in
my faceplate when the real valve change status.

My usercontrol Valve template shoud have a graphic symbol and a text
label - valve symbol. Graphic symbol for this moment is a bitmap -
painted valve where filling colour according to state of real valve.
Gray means the valve is closed, green means opened, red means that
valve is in failure.

When I click on this control the faceplate (a form included in
usercontrol code) should appear to manual control of valve.

So the usercontrol should has at least 3 properties:
- state [for ex. 0 - closed, 1-opened, 2- failure)
- command
- valve label [for ex. VALVE1]

when SCADA read from PLC memory that state of valve changed then
change the property state on my control, the bitmap change to inform
the user that valve change state. If faceplate is opened then it
should also to change state in the valve symbol in faceplate...

I don't want to co synchronize write current state to faceplate
form...it's cost a lot of CPU time... that's why I prefer to use
event...

A usercontrol has to be like "black box" with only some properties
which are use as interface to PLC, and shouldn't need any code outside
the control. The control should provide full functionality itself.
That's why I want faceplate to handle the event of state property
change.

but the problem is how to determine the usercontrol instance name and
how to bind a event to it?

when in InitializeComponent method for my usercontrol form put:

ValveControl.ValveUserControl valve = new ValveUserControl();
valve.StatusChanged += new
ValveUserControl.MyEventHandler(ValveControlForm_StatusChanged);

and then when I change state: valve.uState = 1;
it's work how fine... but this code could should be created automatic
when I put the control on the form...
I cannot create new object I should use reference to object which is
created when I drag control on a container [C# form or SCADA
screen].... but I don't know how to do this...


Maybe my english is too poor to clarify my idea.... sorry :)
 
J

Jeroen van Langen

?Hi, I'm also working in industry with PLC. (writing a HMI application for
pickerlines)

Example:
A simple way could be that you create a Connection component. It's a
component that you can drag onto the form (like a Timer)
This class will build and maintain the connection to the PLC specified on
properties you've entered (hostname/IP/OPC server url/anything you need to
communicate with the PLC)
The first thing you want to do is split the read/write values. Reading
(monitoring) and writing (signaling) should be separated as Pete also wrote
you don't want circular updates.
The connection component builds 2 dictionaries of Item classes. A read
dictionary and a write dictionary.
This connection component should provide methods to give access to the items
so another class can query them.

Next you build a control that has a connection property of type
PLCConnection so you can link them in design. Also you should enter a
ItemName this control should monitor. The control will Query the ItemValue
class from the linked PLCConnection instance and register the ValueChanged
event if it's a read value the event is not necessary when writing.
Now the control will receive events when the ItemValue's value is changed
and invalidates it self.

For read values (uState) the statuscontrol registers the ValueChanged event
of the ItemValue class so the control can invalidate it self.
For write values (uCommand) the PLCConnection registers the ValueChanged
event of the ItemValue class so it can post the new value to the PLC when
the control changes the value.

The next step will be Index components which work like the index of an
array. Because you can static bind the ItemNames to controls. But with a
machine with 20 valves you want to have something like a selector. :)
machine.Valve[12].Status = true
These components will enable you to build the ItemName dynamically.

I could give a code example if you want.

My English is probably worse..

Good luck,
Jeroen
 
M

MKMOBILE

Pete

You are right.

The simplest way is to use a properties...

I create properties for my customcontrol form and now works fine.

Thanks a lot!


:)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top