Press "Enter" to skip to content

Creare, attivare, disattivare controlli a runtime

In risposta ad una domanda posta su Stack overflow  dove un utente chiedeva come creare dei controlli a runtime che simulino una ShowDialog, visto che mi sembrava una richiesta interessante a cui rispondere ho creato un piccolo esempio che effettua esattamente questo. Vediamo come ho fatto.

mainwindow_01

La main window simula un programma con varie funzionalità sulla finestra principale. Lo spazio vuoto è destinato ad accogliere gli user control generati a runtime. Le textbox ed i bottoni sulla sinistra non hanno alcuna funzionalità, mentre i tre bottoni in basso creano i controlli “showdialog”.

I controlli della MainWindow

Come in tutti gli articoli intermediate, listerò cosa c’è nello xaml e commenterò solo l’essenziale a spiegare le funzionalità che vogliamo ottenere.

  • Grid – Contenitore principale di tutto
  • Grid – Crea le 3 colonne dell’area di lavoro
  • Stack panel – posto sulla prima colonna ospita i controlli che stanno sulla zona a sinistra dell’area principale della finestra.
  • TextBlock + TextBox – ve ne sono 3 e simulano un data input sulla finestra principale.
  • ScrollViewer – ControlContainer occupa la colonna centrale dell’area principale della finestra, conterrà gli user control creati a runtime.
  • StackPanel – posto sulla terza colonna, ospita i controlli che stanno sulla zona a destra dell’area principale della finestra.
  • Textblock + TextBox + Buttons – simulano un altra area attiva della finestra principale.
  • StackPanel – posto sulla seconda riga della grid principale, ospita i pulsanti di comando per la visualizzazione degli User control i soli attivi sulla finestra.
  • Button – Tre button che mostrano come generare un controllo al volo e gestire la disattivazione dell’interfaccia fino a che il controllo non sarà “chiuso”

Cosa c’è di importante nello XAML

<StackPanel
	Grid.Row="1"
	Orientation="Horizontal"
	FlowDirection="RightToLeft">
	<Button
		Margin="4,2,4,2"
		Padding="10,2,10,2"
		Content="Open Text Control"
		IsEnabled="{Binding NoControlsOpen}"
		Click="OpenTextControl_Click"/>
	<Button
		Margin="4,2,4,2"
		Padding="10,2,10,2"
		Content="Open Options Control"
		IsEnabled="{Binding NoControlsOpen}"
		Click="OpenOptionsControl_Click"/>
	<Button
		Margin="4,2,4,2"
		Padding="10,2,10,2"
		Content="Open Checkboxes Control"
		IsEnabled="{Binding NoControlsOpen}"
		Click="OpenCheckboxesControl_Click"/>
 
 
</StackPanel>

Quando darete un occhiata al codice XAML vi invito a osservare come io abbia collegato in Binding la property IsEnabled degli Stack Panel e dei 3 button che comandano gli user control ad un campo chiamato NoControlsOpen. Questa property del mio viewmodel comanda l’attivazione e disattivazione dei controlli per simulare lo ShowDialog.

Gli User Control

I tre user control che possono essere creati e caricati dinamicamente, sono tre semplici oggetti che simulano delle  mini form di richiesta dati.

TextControl

TextControl_01

Contiene un titolo ed una casella di testo multilinea, e il bottone di chiusura.

OptionControl

optioncontrol_01

Contiene un titolo e 5 RadioButton che permettono una scelta singola ed il bottone di chiusura.

CheckControl

checkcontrol_01

Contiene un titolo, cinque checkbox quindi una scelta multipla e il bottone per chiudere il controllo.

Ciascuno degli User control usa se stesso come ViewModel ed espone le property ed i metodi per modificare il proprio contenuto e leggere quello che  l’utente ha modificato prima di chiudere il controllo.

 

Ciascuno dei 3 controlli, al suo interno contiene il seguente codice:

private void CloseControl_Click(object sender, RoutedEventArgs e)
{
OnCloseMe(new EventArgs());
}


public event EventHandler CloseMe;


protected virtual void OnCloseMe(EventArgs e)
{
if (CloseMe != null)
{
CloseMe(this, e);
}
}

Questo codice, definisce un evento chiamato CloseMe, che viene sollevato alla pressione del tasto Chiudi, e permette alla Window di reagire in modo da acquisire i dati modificati, e chiudere lo User Control riprendendo il controllo dell’interfaccia utente.

Importante!

public TextControl()
{
InitializeComponent();
this.DataContext = this;
}

Questo è il costruttore di uno degli User control, tutti e tre hanno lo stesso codice al suo interno, ovvero il codice che indica al controllo che è il ViewModel di se stesso, questo ci permette il binding dei controlli inseriti sullo User Control alle property pubbliche definite nel codice che saranno accessibili alla Window per leggere quanto l’utente ha scritto o selezionato su ognuno degli User control.

Il codice di MainWindow

Vediamo ora come abbiamo implementato il codice funzionale, nella finestra principale del programma.

public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}

Anche per la MainWindow, abbiamo implementato la versione base di MVVM, indicando alla finestra che il suo ViewModel è lei stessa.

public const string FLD_NoControlsOpen = "NoControlsOpen";

public bool NoControlsOpen
{
get
{
return (bool)this.GetValue(NoControlsOpenProperty);
}
set
{
this.SetValue(NoControlsOpenProperty, value);
}
}


public static readonly DependencyProperty NoControlsOpenProperty = DependencyProperty.Register(
FLD_NoControlsOpen, typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

La Dependency Property più importante, infatti questo boolean verrà posto a True o False dai gestori degli User Control per attivare e disattivare la User Interface della window quando necessario.


private void OpenTextControl_Click(object sender, RoutedEventArgs e)
{
ControlContainer.Content = null;
TextControl txt = new TextControl();
txt.TitleText = string.Format("This is a text control opened on {0} {1}", DateTime.Now.ToShortDateString(), DateTime.Now.ToLongTimeString());
txt.TextValue = "Please write some text";
txt.CloseMe += Txt_CloseMe;
ControlContainer.Content = txt;
NoControlsOpen = false;
}

private void Txt_CloseMe(object sender, EventArgs e)
{
TextControl txt = sender as TextControl;
if (txt != null)
{
MessageBox.Show(string.Format("The control value is: {0}", txt.TextValue), "Text control closed");
ControlContainer.Content = null;
NoControlsOpen = true;

}
}

Il codice che gestisce il bottone che apre il controllo Testo, come possiamo vedere, creiamo un istanza del controllo, aggiorniamo le sue property e implementiamo un event handler per il suo evento CloseMe. Inseriamo il controllo nel ControlContainer e poniamo a false l’indicatore che regola l’attivazione (o in questo caso disattivazione) dei controlli della Window.
L’Event handler oltre a eseguire del codice per mostrare che possiamo interagire con il controllo, ne effettua la chiusura, eliminandolo dall’interno del ControlContainer e resetta l’indicatore che riattiva i controlli della Window.

Il codice per gli altri due controlli è praticamente identico, salvo per il fatto che vi sono delle descrizioni in più da indicare al controllo prima di attivarlo.

Come funziona?

textcontrol_open

Se clicchiamo su Open Text Control il nostro User control apparirà nella zona centrale della window, e le textbox, ed i button saranno disattivati.

textcontrol_closed

Premendo il bottone di chiusura del controllo, verrà eseguito il codice che legge il suo contenuto.

textcontrol_closed2

Una volta premuto OK, il controllo viene “chiuso” e sparisce riattivando le textbox e i button della finestra.

optioncontrol_open

Funziona in modo identico anche per il controllo con le options.

checkcontrol_open

E per il controllo con le Checkbox.

Riepilogo

In questo progetto possiamo vedere:

  • Come creare una struttura per poter contenere dei controlli creati a runtime
  • Come creare degli user control che possono essere creati a runtime, configurati e che sollevano un evento all’azione utente (CloseMe).
  • Come utilizzare il Binding ad una property Bool della property IsEnabled dei controlli di una window affinché siano automaticamente disattivati quando uno User control viene generato.
  • Come intercettare l’evento CloseMe dello user control per simularne la chiusura e riattivare i controlli all’interno della window.
  • Come utilizzare MVVM in modalità base, utilizzando le classi Window e UserControl stesse come ViewModel.

Potete scaricare il progetto esempio dal link qui indicato:

Per qualsiasi domanda, osservazione, commento, approfondimento, o per segnalare un errore, potete usare il link alla form di contatto in cima alla pagina.