PDA

View Full Version : [C#]intercettare oggetti a run time


RaouL_BennetH
15-10-2008, 09:07
Ciao a tutti :)

Ho scritto una piccolissima classe che mi serve per avere un menu completo per la mia applicazione senza doverlo ogni volta disegnare sui forms dal designer. Il tutto mi funziona correttamente, nel senso che da un form qualsiasi basta che mi richiamo nell'evento Load:


ApplicationMenu menu = new ApplicationMenu();
menu.Setup();


Questo menu ovviamente comprende diversi bottoni.
Stesso nella classe ApplicationMenu ho provveduto a scrivere i vari eventi:


//blablacode
ToolStripButton nuovo = new ToolStripButton();
nuovo.Text = "NUOVO";
nuovo.ForeColor = System.Drawing.Color.White;
nuovo.DisplayStyle = ToolStripItemDisplayStyle.Text;
nuovo.Click += new EventHandler(nuovo_Click);

//blablacode


void nuovo_Click(object sender, EventArgs e)
{
//in questo evento, dovrei, in base al form
//nel quale mi trovo, abilitare alcuni controlli
//presenti sul form stesso.... come fare?!?!?
}


Grazie in anticipo.

RaouL.

gugoXX
15-10-2008, 10:44
Ciao a tutti :)
...
RaouL.

Parere mio il titolo e' sbagliato, nel senso che il modo migliore e' farlo a compile-time, con un buon disegno.

Primo metodo, ortodosso, e' quello di creare con Controllo, che potra' poi essere aggiunto (trascinato) alle form che lo utilizzeranno.
I controlli hanno una proprieta' che punta alla Form su cui risiedono (non ricordo il nome ora, e' un po' tanto che non uso WinForm)

Alternativamente puoi invece costruire una classe come quella che hai creato ora, aggiungendo tu a mano una proprieta' di tipo Form.
Puoi quindi dotare di un metodo la tua classe, tipo
public void Register(Form parentForm);
che dovrai chiamare dalla Init della Form su cui la tua classe dovra' agire, praticamente registrandosi.


// Sulla Form
public override InInit(boh)
{
....
IstanzaDellaMiaClasse.Register(this);
....
}


Cosi' facendo di nuovo la tua classe sapra' chi e' la form che la ospita.

RaouL_BennetH
15-10-2008, 11:35
Grazie gugoXX.

Concettualmente credo di aver inteso cosa suggerisci, ma non riesco a metterlo in pratica :(

Ad ogni modo, questo è il codice della classe che genera il menu:


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace TestReusableMenu
{
class ReusableMenu
{
private ToolStrip formMenu;

public ToolStrip MenuSetup()
{
formMenu = new ToolStrip();
formMenu.BackColor = System.Drawing.Color.Transparent;
formMenu.Dock = DockStyle.Top;
formMenu.Font = new System.Drawing.Font("Verdana", 8);
formMenu.GripStyle = ToolStripGripStyle.Hidden;
ToolStripButton nuovo = new ToolStripButton();
nuovo.Text = "NUOVO";
nuovo.ForeColor = System.Drawing.Color.White;
nuovo.DisplayStyle = ToolStripItemDisplayStyle.Text;
nuovo.Click += new EventHandler(nuovo_Click);
ToolStripButton salva = new ToolStripButton();
salva.Text = "SALVA";
salva.ForeColor = System.Drawing.Color.White;
salva.DisplayStyle = ToolStripItemDisplayStyle.Text;
salva.Click += new EventHandler(salva_Click);
ToolStripButton annulla = new ToolStripButton();
annulla.Text = "ANNULLA";
annulla.ForeColor = System.Drawing.Color.White;
annulla.DisplayStyle = ToolStripItemDisplayStyle.Text;
annulla.Click += new EventHandler(annulla_Click);
ToolStripButton modifica = new ToolStripButton();
modifica.Text = "MODIFICA";
modifica.ForeColor = System.Drawing.Color.White;
modifica.DisplayStyle = ToolStripItemDisplayStyle.Text;
modifica.Click += new EventHandler(modifica_Click);
ToolStripButton aggiorna = new ToolStripButton();
aggiorna.Text = "AGGIORNA";
aggiorna.ForeColor = System.Drawing.Color.White;
aggiorna.DisplayStyle = ToolStripItemDisplayStyle.Text;
aggiorna.Click += new EventHandler(aggiorna_Click);
ToolStripButton elimina = new ToolStripButton();
elimina.Text = "ELIMINA";
elimina.ForeColor = System.Drawing.Color.White;
elimina.DisplayStyle = ToolStripItemDisplayStyle.Text;
elimina.Click += new EventHandler(elimina_Click);
ToolStripButton stampa = new ToolStripButton();
stampa.Text = "STAMPA";
stampa.ForeColor = System.Drawing.Color.White;
stampa.DisplayStyle = ToolStripItemDisplayStyle.Text;
stampa.Click += new EventHandler(stampa_Click);
ToolStripButton esci = new ToolStripButton();
esci.Text = "ESCI";
esci.ForeColor = System.Drawing.Color.White;
esci.DisplayStyle = ToolStripItemDisplayStyle.Text;
esci.Click += new EventHandler(esci_Click);
ToolStripSeparator s0 = new ToolStripSeparator();
s0.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s1 = new ToolStripSeparator();
s1.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s2 = new ToolStripSeparator();
s2.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s3 = new ToolStripSeparator();
s3.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s4 = new ToolStripSeparator();
s4.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s5 = new ToolStripSeparator();
s5.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s6 = new ToolStripSeparator();
s6.ForeColor = System.Drawing.Color.White;
ToolStripSeparator s7 = new ToolStripSeparator();
s7.ForeColor = System.Drawing.Color.White; ;

formMenu.Items.Insert(0, nuovo);
formMenu.Items.Insert(1, s0);
formMenu.Items.Insert(2, salva);
formMenu.Items.Insert(3, s1);
formMenu.Items.Insert(4, annulla);
formMenu.Items.Insert(5, s2);
formMenu.Items.Insert(6, modifica);
formMenu.Items.Insert(7, s3);
formMenu.Items.Insert(8, aggiorna);
formMenu.Items.Insert(9, s4);
formMenu.Items.Insert(10, elimina);
formMenu.Items.Insert(11, s5);
formMenu.Items.Insert(12, stampa);
formMenu.Items.Insert(13, s6);
formMenu.Items.Insert(14, esci);
formMenu.Items.Insert(15, s7);
return formMenu;

}

void stampa_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void elimina_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void modifica_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void salva_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void annulla_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}

void aggiorna_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");

}

void esci_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");


}

void nuovo_Click(object sender, EventArgs e)
{
throw new Exception("The method or operation is not implemented.");

}

}
}

//da qualsiasi form:

ReusableMenu rm = new ReusableMenu();
this.Controls.Add(rm.MenuSetup());


Potrei anche pensare di passare a MenuSetup() un argomento di tipo Form, ma non ho capito come potrei 'registrarlo' per fare in modo che gli eventi
dei bottoni riconoscano il form che li chiama.

Grazie ancora.

RaouL.

gugoXX
15-10-2008, 12:00
Ciao.

No guarda. Quello che ti serve e' proprio un controllo custom.
Prova a fare cosi'.
Nel tuo progetto clicca con il destro e aggiungi uno user-control, chiamalo MyToolStripControl
Sullo user control trascina la toolstrip, rendila Dock-Fill e piazzagli sopra tutti gli altri controlli (ToolStripButton, label, etc.) come se al posto di essere un controllo riusabile fosse il vero controllo che ti serve.
Alla fine di tutto compila e guarda se non hai errori.
A questo punto, se tutto e' andato bene, dovresti poter andare sulla form e tra i controlli disponibili da poterci trascinare sopra dovresti trovarti anche il tuo MyToolStripControl.
Trascini e lo usi.

E questo e' il primo passo.

E' probabile che poi tu debba notificare qualcosa alla Form padre potrai fare cosi'.
Immagina di aver trascinato un pulsante sul tuo user-control, chiamato: FaiLaPizza
Ebbene, potrai aggiungere un evento al tuo controllo, chiamato magari
FaiLaPizzaClicked, con un delegate particolare per poter passare eventuali informazioni insieme al pulsante, che potrebbero anche non esserci pero'.

Da dentro il controllo quindi intercetterai il OnClick del pulsante (in pratica nell'edito cliccherai sul pulsante della toolstrip, e ti verra' creato il codice necessario) e nella funzione semplicemente lancerai l'evento FaiLaPizzaClicked

Avendo tu usato la keyword "event" da dentro il controllo, ne consegue che ogni form su cui trascinerai questo tuo controllo avra' a disposizione l'evento OnFaiLaPizzaClicked, dentro il quale scriverai il codice che vorrai far fare alla form ogni volta che qualcuno premera' quel pulsante della toolbar.

E' piu' facile vederlo che descriverlo:

// Codice nel controllo custom, sulla cui toolstrip ho trascinato un solo pulsante
namespace wfaapp
{
public partial class MyToolStrip : UserControl
{
public MyToolStrip()
{
InitializeComponent();
}

public delegate void FaiLaPizzaHandler(string message);
public event FaiLaPizzaHandler FaiLaPizza;

private void toolStripButton1_Click(object sender, EventArgs e)
{
FaiLaPizza("Margherita");
}
}
}



//Codice nella form, sulla quale per ora ho trascinato solamente il mio controllo custom
// Per fare comparire il codice di private void myToolStrip1_FaiLaPizza(string message)
// se tutto e' stato fatto bene e' sufficiente andare sulle proprieta'
// del controllo custom trascinato sulla form,
// scegliere Events invece che Properties e nella lista dovrebbe esserci anche
// FaiLaPizza. doppio click li sopra e ti viene creato il prototipo da riempire come segue
namespace wfaapp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void myToolStrip1_FaiLaPizza(string message)
{
string stmp = string.Format("Mi e' stata richiesta una {0}",message);
MessageBox.Show(stmp);
}
}
}



Quando clicco sul pulsante della toolstrip del controllo della form, mi viene aperta una messagebox con scritto "Mi e' stata richiesta una Margherita".
Ovviamente al posto di Margherita, e al posto di string, puoi passare qualunque informazione tu abbia bisogno dal controllo alla form.

RaouL_BennetH
15-10-2008, 15:06
Esempio davvero illuminante :ave:

Grazie davvero :)

RaouL.

RaouL_BennetH
15-10-2008, 16:18
Questo è il mio piccolissimo concetto di come sto sviluppando dopo il tuo aiuto:



//File SimpleToolStrip.cs
using System;
using System.Drawing;
using System.Windows.Forms;

namespace GeneralMenu
{
public partial class SimpleToolStrip: UserControl
{

public SimpleToolStrip()
{
InitializeComponent();
}

//proprietà che mi serve per ottenere gli Items presenti
//sul menu generico
public virtual ToolStripItemCollection Items
{
get { return customMenu.Items; }
}

public delegate void OnNewActionHandler(string message);
public delegate void OnExitActionHandler(string message);

public event OnNewActionHandler OnNewAction;
public event OnExitActionHandler OnExitAction;

private void btnNew_Click(object sender, EventArgs e)
{
OnNewAction("Abilitazione Controlli Del Form");
}

private void btnExit_Click(object sender, EventArgs e)
{
OnExitAction("Richiesta chiusura Form corrente");
}
}
}

//File FormCleaner.cs
//Classe che serve a svuotare oggetti vari dopo le operazioni
//tipiche di inserimento, ricerca etc...
//e a settare il menu in base ai pulsanti premuti

using System;
using System.Windows.Forms;

namespace GeneralMenu
{
public class FormCleaner
{
private const int fixedItems = 14;

public void OnLoad(SimpleToolStrip st)
{

/*ad ogni load di un form sul quale
sarà presente il menu, soltanto
i pulsanti '0' e '14' saranno abilitati
*/


for (int i = 2; i < fixedItems; i += 2)
{
st.Items[i].Enabled = false;
}
}

}
}


Resto comunque in attesa di preziosi suggerimenti.

RaouL.

gugoXX
15-10-2008, 16:30
Ciao.
Se vuoi fare le cose pulite non dovresti permettere alla form padre di interagire con i controlli del tuo user control in modo diretto.

Sarebbe piu' opportuno aggiungere i metodi che ti servono al tuo controllo figlio.
Es: Vorrei dare la possibilita' di abilitare solo i pulsanti 'dispari'?
Allora aggiungo un metodo pubblico tipo

public void EnableOddButtons()
{
//
}

e solo lui, dall'interno, sara' autorizzato a giocare con la toolstrip e i suoi componenti.
Che sono stati aggiunti privati se hai notato, ed un motivo ci sara'...

A fare le cose come si deve, la form padre dovrebbe solamente ricevere eventi e settare stati mediante appositi metodi messi a disposizione dallo user-control.
Domani potresti voler riscrivere il tuo controllo user, che magari invece della toolstrip e' invece un insieme di pulsanti veri e propri, con label, etc.
Ti bastera' richiamare gli eventi segunedo la logica, e tutto funzionera', senza dover costringere la form ad assumere che c'e' qualcosa di particolare (come una ToolStripItemCollection) all'interno del tuo user control, che domani appunto potrebbe non esserci piu'.

RaouL_BennetH
16-10-2008, 09:42
Ciao gugoXX :)

Quindi, se non ho capito male, mi conviene sempre configurare i comportamenti all'interno del mio componente ?

gugoXX
16-10-2008, 10:00
Ciao gugoXX :)

Quindi, se non ho capito male, mi conviene sempre configurare i comportamenti all'interno del mio componente ?

Si' esatto.
E' una regola d'oro della programmazione ad oggetti.
Quando devi romperla e' perche' molto probabilmente non hai disegnato bene.

Esponi i comportamenti da fuori. Ogni tuo oggetto dovrebbe risultare come una semplice interfaccia, tali per cui possa essere completamente sostituito con una eventuale nuova versione del componente. Qualita' che e' parente con la riusabilita' del componente stesso.