Technology Experience
.NET World

Utilizzare OpenFileDialog e SaveFileDialog con Lightswitch

Una delle cose più comuni all’interno di un’applicazione, sia Desktop che Web, è fornire all’utente la possibilità di aprire e salvare files sul proprio PC. Potrebbe trattarsi di una fattura in formato pdf, oppure di un semplice file di testo, xml, e via dicendo. Le possibilità sono innumerevoli, e dipendono ovviamente dal tipo di applicazione che state sviluppando.

Dal punto di vista developer, questa cosa si ottiene con le classi OpenFileDialog e SaveFileDialog. Queste classi sono disponibili allo stesso modo con Windows Forms, WPF ed ovviamente Silverlight. Il che tocca ovviamente anche il nuovo mondo Lightswitch. Arriviamo al dunque.

Per permettere all’utente l’apertura di un file è necessario scrivere qualche riga di codice. Apriamo lo Screen Designer relativo allo screen su cui vogliamo gestire questa cosa, e per semplicità aggiungiamo un pulsante nuovo, chiamato “PrintInvoice”.

Per editare il codice è sufficiente cliccare con il destro sul Button appena aggiunto e successivamente fare click su Edit Execute Code. In condizioni normali scriveremmo il codice seguente:

OpenFileDialog dialog = new OpenFileDialog();

partial void Print_Execute()
{
    var result = dialog.ShowDialog().GetValueOrDefault();

    if (result)
    {

    }
}

 

Ovvero: istanziamo un oggetto OpenFileDialog come membro privato della classe, e sul click del Button invochiamo la ShowDialog() per dare la scelta all’utente. Sfortunatamente con Lightswitch le cose sono un po’ diverse:

  • Innanzitutto l’istanziazione della classe OpenFileDialog deve avvenire nel thread UI (comunque facilmente accessibile attraverso Microsoft.LightSwitch.Threading.Dispatchers.Main)
  • Se anche risolvessimo il punto sopra, ci scontreremmo con un altro problema, tipico dello sviluppo Silverlight. Ovvero la chiamata a ShowDialog() deve avvenire sempre e comunque come diretta conseguenza di un’interazione fatta dall’utente. Nel nostro caso sarebbe il semplice click del mouse, ma evidentemente Lightswitch aggiunge qualche strato software che impedisce questa cosa. L’architettura che c’è dietro i Button creati e gestiti con Lightswitch – infatti – vengono gestiti attraverso il motore di binding di WPF/Silverlight, applicando il pattern MVVM. Vediamo infatti che dobbiamo gestire gli eventi Execute e CanExecute, che derivano direttamente dall’interfaccia ICommand.

Quindi, difatto siamo bloccati. Cosa dobbiamo fare per risolvere il problema? Bisogna complicarsi la vita, come sempre! Sorriso

Innanzitutto, andiamo a gestire l’evento Created dello Screen che ci interessa e scriviamo questo codice:

   1:  partial void InvoicesListDetail_Created()
   2:  {
   3:      Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
   4:      {
   5:          dialog = new SaveFileDialog();
   6:          dialog.DefaultExt = "pdf";
   7:          dialog.Filter = "Documenti Pdf (*.pdf)|*.pdf|Tutti i files (*.*)|*.*";
   8:      });
   9:   
  10:      var printInvoiceButton = this.FindControl("PrintInvoice");
  11:      printInvoiceButton.ControlAvailable += printInvoiceButton_ControlAvailable;
  12:  }

 

In fase di creazione dello Screen, utilizzo il thread UI per inizializzare l’oggetto dialog, definito – come prima – come membro della classe. Oltre a questo, utilizzo l’extension method FindControl per ottenere un riferimento al Button che ci interessa.

Una cosa importante: il metodo FindControl, come già detto, è un extension method. Assicuratevi di avere la riga using Microsoft.LightSwitch.Presentation.Extensions, altrimenti non potrete mai utilizzarlo.

Una volta ottenuto il riferimento al Button, utilizzando il suo nome che avete impostato nello Screen Designer, ne sottoscrivo l’evento ControlAvailable. Questo, finalmente, mi porta a poter gestire l’evento Click.

   1:  void printInvoiceButton_ControlAvailable(object sender, ControlAvailableEventArgs e)
   2:  {
   3:      this.FindControl("PrintInvoice").ControlAvailable -=
   4:          printInvoiceButton_ControlAvailable;
   5:      var button = (Button)e.Control;
   6:      button.Click += button_Click;
   7:  }
   8:   
   9:  void button_Click(object sender, RoutedEventArgs e)
  10:  {
  11:      dialogResult = dialog.ShowDialog().GetValueOrDefault();
  12:  }

 

Nulla di particolarmente complicato. All’interno dell’evento Click possiamo visualizzare all’utente la finestra di dialogo, chiamando semplicemente il metodo ShowDialog(). Qui si sfrutta un comportamento particolare di Lightswitch: quando cliccate su un Button gestito secondo questa tecnica, prima viene richiamato l’evento Click, e solo successivamente viene eseguito il codice contenuto nell’Execute, che a questo punto conterrà una cosa simile a questa:

partial void PrintInvoice_Execute()
{
    if (dialogResult)
    {

    }
}

 

Il fatto di aver cliccato sul Button, quindi, prima visualizza la dialog (evento Click). Quando l’utente la chiude, sia scegliendo un file, sia cliccando su Annulla, viene eseguito l’Execute del Button associato. A questo punto si testa il valore restituito dalla dialog e si agisce di conseguenza.

Conclusione

Ok, il problema è risolvibile senza grossi problemi, ma il tutto mi sembra una forzatura, e ci richiede di scrivere codice “a basso livello”, che va un po’ in direzione opposta rispetto alla filosofia di Lightswitch. Che dire, magari la cosa verrà migliorata in futuro, con qualche patch o fix. Staremo a vedere!

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

This site uses Akismet to reduce spam. Learn how your comment data is processed.