Cenni preliminari sulle finestre di dialogo
Nelle applicazioni autonome è in genere presente una finestra principale in cui vengono visualizzati i dati principali su cui si basa il funzionamento dell'applicazione e in cui vengono esposte le funzionalità di elaborazione dei dati stessi attraverso meccanismi dell'user interface (UI) quali barre dei menu, barre degli strumenti e barre di stato. In un'applicazione più complessa sono inoltre disponibili finestre aggiuntive per l'esecuzione delle operazioni riportate di seguito:
Visualizzazione di informazioni specifiche agli utenti.
Raccolta delle informazioni immesse dagli utenti.
Visualizzazione e raccolta di informazioni.
Questi tipi di finestre, noti come finestre di dialogo, si suddividono in due tipi: modali e non modali.
Una finestra di dialogo modale viene visualizzata da una funzione quando tale funzione, per continuare, deve ricevere ulteriori dati dall'utente. Poiché la raccolta dei dati da parte della funzione dipende dalla finestra di dialogo modale, finché quest'ultima rimane aperta l'utente non potrà attivare altre finestre. Nella maggior parte dei casi, una finestra di dialogo modale può essere chiusa dall'utente tramite la pressione di un pulsante OK o Annulla. Se preme il pulsante OK, l'utente ha immesso dei dati che desidera vengano elaborati dalla funzione. Se preme il pulsante Annulla, l'utente desidera arrestare l'esecuzione della funzione. Gli esempi più comuni di finestre di dialogo modali sono dati dalle finestre di apertura, salvataggio e stampa dei dati.
Una finestra di dialogo non modale non impedisce a un utente di attivare altre finestre mentre è aperta. Ad esempio, se un utente desidera cercare occorrenze di una determinata parola in un documento, dalla finestra principale verrà spesso aperta una finestra di dialogo in cui l'utente dovrà immettere la parola che desidera cercare. Poiché la ricerca di una parola non impedisce all'utente di modificare il documento, la finestra di dialogo non deve essere modale. In una finestra di dialogo non modale è senz'altro disponibile un pulsante Chiudi per la sua chiusura ed eventualmente ulteriori pulsanti per l'esecuzione di funzioni specifiche, ad esempio un pulsante Trova successivo per cercare la parola successiva corrispondente ai criteri della ricerca.
Windows Presentation Foundation (WPF) consente di creare molti tipi di finestre di dialogo, incluse finestre di messaggio, finestre di dialogo comuni e finestre di dialogo personalizzate. In questo argomento vengono illustrati i diversi tipi di finestre di dialogo e in Esempio di finestra di dialogo (la pagina potrebbe essere in inglese) sono disponibili alcuni esempi.
Nel presente argomento sono contenute le seguenti sezioni.
- Finestre di messaggio
- Finestre di dialogo comuni
- Finestre di dialogo personalizzate
- Argomenti correlati
Finestre di messaggio
Una finestra di messaggio è una finestra di dialogo che può essere utilizzata per visualizzare informazioni di testo e consentire agli utenti di prendere decisioni con i pulsanti. Di seguito è illustrata una finestra di messaggio in cui vengono visualizzate informazioni di testo, viene posta una domanda e in cui sono disponibili tre pulsanti per fornire una risposta.
Per creare una finestra di messaggio, si utilizza la classe MessageBox, che consente di configurare il testo, il titolo, l'icona e i pulsanti della finestra tramite codice simile a quello riportato di seguito.
' Configure the message box to be displayed
Dim messageBoxText As String = "Do you want to save changes?"
Dim caption As String = "Word Processor"
Dim button As MessageBoxButton = MessageBoxButton.YesNoCancel
Dim icon As MessageBoxImage = MessageBoxImage.Warning
// Configure the message box to be displayed
string messageBoxText = "Do you want to save changes?";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
Per visualizzare una finestra di messaggio, chiamare il metodo static Show, come illustrato nel codice riportato di seguito.
' Display message box
MessageBox.Show(messageBoxText, caption, button, icon)
// Display message box
MessageBox.Show(messageBoxText, caption, button, icon);
Quando il codice per la visualizzazione di una finestra di messaggio deve rilevare ed elaborare la decisione dell'utente (quale pulsante è stato premuto), può analizzare il risultato della finestra di messaggio, come illustrato nel codice riportato di seguito.
' Display message box
Dim result As MessageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon)
' Process message box results
Select Case result
Case MessageBoxResult.Yes
' User pressed Yes button
' ...
Case MessageBoxResult.No
' User pressed No button
' ...
Case MessageBoxResult.Cancel
' User pressed Cancel button
' ...
End Select
// Display message box
MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (result)
{
case MessageBoxResult.Yes:
// User pressed Yes button
// ...
break;
case MessageBoxResult.No:
// User pressed No button
// ...
break;
case MessageBoxResult.Cancel:
// User pressed Cancel button
// ...
break;
}
Per ulteriori informazioni sull'utilizzo delle finestre di messaggio, vedere MessageBox, Esempio di finestra di messaggio ed Esempio di finestra di dialogo (le pagine potrebbero essere in inglese).
Sebbene MessageBox semplifichi l'utilizzo delle finestre di dialogo da parte dell'utente, MessageBox è il solo tipo di finestra visualizzabile dalle applicazioni eseguite in un sandbox di sicurezza con attendibilità parziale (vedere Sicurezza (WPF)), ad esempio le XAML browser applications (XBAPs).
Nella maggior parte delle finestre di dialogo vengono visualizzati e raggruppati dati più complessi del risultato di una finestra di messaggio, ad esempio testo, selezione (caselle di controllo), selezione a esclusione reciproca (pulsanti di opzione) e selezione in elenchi (caselle di riepilogo, caselle combinate, elenchi a discesa). Per questo motivo, Windows Presentation Foundation (WPF) fornisce molte finestre di dialogo comuni e consente di crearne di personalizzate, sebbene l'utilizzo di entrambe sia limitato ad applicazioni eseguite con attendibilità totale.
Finestre di dialogo comuni
In Windows è implementata una varietà di finestre di dialogo riutilizzabili comuni a tutte le applicazioni, incluse le finestre di dialogo per l'apertura, il salvataggio e la stampa di file. Poiché queste finestre di dialogo sono implementate dal sistema operativo, possono essere condivise da tutte le applicazioni eseguite nel sistema operativo, con notevoli vantaggi in termini della coerenza di utilizzo: se un utente utilizza con frequenza una finestra di dialogo basata sul sistema operativo in un'applicazione, non dovrà imparare a utilizzare la stessa finestra in altre applicazioni. Poiché queste finestre di dialogo sono disponibili in tutte le applicazioni e poiché consentono un'esperienza utente coerente, sono note come finestre di dialogo comuni.
Windows Presentation Foundation (WPF) incapsula le finestre di dialogo comuni di apertura, salvataggio e stampa di file e le espone come classi gestite da utilizzare in applicazioni autonome. In questo argomento vengono forniti alcuni cenni preliminari su ognuna.
Finestra di dialogo Apri
La finestra di dialogo Apri illustrata di seguito viene utilizzata dalla funzionalità di apertura file per recuperare il nome di un file da aprire.
La finestra di dialogo Apri comune viene implementata come classe OpenFileDialog e inserita nello spazio dei nomi Microsoft.Win32. Nel codice riportato di seguito viene illustrato come creare, configurare e visualizzare questa finestra di dialogo e come elaborare il relativo risultato.
' Configure open file dialog box
Dim dlg As New Microsoft.Win32.OpenFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".txt" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension
' Show open file dialog box
Dim result? As Boolean = dlg.ShowDialog()
' Process open file dialog box results
If result = True Then
' Open document
Dim filename As String = dlg.FileName
End If
// Configure open file dialog box
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
Per ulteriori informazioni sulla finestra di dialogo Apri, vedere Microsoft.Win32.OpenFileDialog.
Nota |
---|
OpenFileDialog può essere utilizzato per il recupero sicuro di nomi file da parte di applicazioni eseguite con attendibilità parziale (vedere Sicurezza (WPF)). |
Finestra di dialogo Salva con nome
La finestra di dialogo Salva con nome illustrata di seguito viene utilizzata dalla funzionalità di salvataggio file per recuperare il nome di un file da salvare.
La finestra di dialogo Salva con nome comune viene implementata come classe SaveFileDialog e inserita nello spazio dei nomi Microsoft.Win32. Nel codice riportato di seguito viene illustrato come creare, configurare e visualizzare questa finestra di dialogo e come elaborare il relativo risultato.
' Configure save file dialog box
Dim dlg As New Microsoft.Win32.SaveFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".text" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension
' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()
' Process save file dialog box results
If result = True Then
' Save document
Dim filename As String = dlg.FileName
End If
// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
Per ulteriori informazioni sulla finestra di dialogo Salva con nome, vedere Microsoft.Win32.SaveFileDialog.
Finestra di dialogo Stampa
La finestra di dialogo Stampa illustrata di seguito viene utilizzata dalla funzionalità di stampa per la scelta e la configurazione della stampante su cui stampare dati.
La finestra di dialogo Stampa comune viene implementata come classe PrintDialog e inserita nello spazio dei nomi System.Windows.Controls. Nel codice riportato di seguito viene illustrato come creare, configurare e visualizzare una finestra di dialogo di questo tipo.
' Configure printer dialog box
Dim dlg As New PrintDialog()
dlg.PageRangeSelection = PageRangeSelection.AllPages
dlg.UserPageRangeEnabled = True
' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()
' Process save file dialog box results
If result = True Then
' Print document
End If
// Configure printer dialog box
System.Windows.Controls.PrintDialog dlg = new System.Windows.Controls.PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Print document
}
Per ulteriori informazioni sulla finestra di dialogo Stampa, vedere System.Windows.Controls.PrintDialog. Per informazioni dettagliate sulla stampa in WPF, vedere Cenni preliminari sulla stampa.
Finestre di dialogo personalizzate
Sebbene le finestre di dialogo comuni siano utili e debbano essere utilizzate quando possibile, non supportano i requisiti delle finestre di dialogo specifiche di vari domini. In questi casi, è necessario creare finestre di dialogo personalizzate. Come verrà illustrato in seguito, una finestra di dialogo è una finestra con particolari comportamenti. Poiché l'oggetto Window implementa tali comportamenti, utilizzarlo per creare finestre di dialogo modali e non modali personalizzate.
Creazione di una finestra di dialogo modale personalizzata
In questo argomento viene illustrato come utilizzare l'oggetto Window per creare un'implementazione tipica di finestra di dialogo modale, utilizzando come esempio la finestra di dialogo Margins; vedere a questo proposito Esempio di finestra di dialogo (la pagina potrebbe essere in inglese). Di seguito viene illustrata la finestra di dialogo Margins.
Configurazione di una finestra di dialogo modale
L'interfaccia utente di una finestra di dialogo tipica include gli elementi riportati di seguito:
I diversi controlli necessari per raccogliere i dati desiderati.
Pulsante OK su cui l'utente fa clic per chiudere la finestra di dialogo, tornare alla funzione e continuare l'elaborazione.
Pulsante Annulla su cui l'utente fa clic per chiudere la finestra di dialogo e interrompere l'elaborazione da parte della funzione.
Pulsante Chiudi nella barra del titolo.
Icona.
Pulsanti di riduzione a icona, ingrandimento e ripristino.
Menu di sistema per ridurre a icona, ingrandire, ripristinare e chiudere la finestra di dialogo.
Apertura sopra e al centro della finestra da cui è stata aperta la finestra di dialogo.
Poiché le finestre di dialogo devono essere, per quanto possibile, ridimensionabili, per impedire che diventino troppo piccole e per fornire utili dimensioni predefinite, è necessario impostare sia dimensioni minime sia dimensioni predefinite.
Il tasto ESC dovrebbe essere configurato come tasto di scelta rapida per la pressione del pulsante Annulla. Questo risultato si ottiene impostando la proprietà IsCancel del pulsante Annulla su true.
Il tasto INVIO dovrebbe essere configurato come tasto di scelta rapida per la pressione del pulsante OK. Questo risultato si ottiene impostando la proprietà IsDefault del pulsante OK su true.
Nel codice riportato di seguito viene illustrata questa configurazione.
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarginsDialogBox"
xmlns:local="clr-namespace:SDKSample"
Title="Margins"
Height="190"
Width="300"
MinHeight="10"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
<Grid>
...
<!-- Accept or Cancel -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
<Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
</StackPanel>
</Grid >
</Window>
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
Public Sub New()
Me.InitializeComponent()
End Sub
...
End Class
End Namespace
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
public MarginsDialogBox()
{
InitializeComponent();
}
...
}
}
L'esperienza utente relativa all'utilizzo di una finestra di dialogo si estende anche alla barra dei menu della finestra da cui viene aperta la finestra di dialogo. Quando una voce di menu attiva una funzione la cui elaborazione richiede interazione da parte dell'utente tramite una finestra di dialogo, nell'intestazione della voce di menu saranno visibili dei puntini di sospensione, come illustrato di seguito.
<!--Main Window-->
...
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />
Quando una voce di menu attiva una funzione che comporta la visualizzazione di una finestra di dialogo che non richiede interazione da parte dell'utente, ad esempio una finestra di dialogo Informazioni su, i puntini di sospensione non sono necessari.
Apertura di una finestra di dialogo modale
Una finestra di dialogo viene in genere visualizzata in seguito alla selezione, da parte dell'utente, di una voce di menu per l'esecuzione di una funzione specifica di un dominio, ad esempio l'impostazione dei margini di un documento in un elaboratore di testo. La visualizzazione di una finestra come una finestra di dialogo è simile alla visualizzazione di una normale finestra, sebbene richieda operazioni di configurazione specifiche. L'intero processo di creazione di un'istanza, di configurazione e di apertura di una finestra di dialogo viene illustrato nel codice riportato di seguito.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
...
Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Instantiate the dialog box
Dim dlg As New MarginsDialogBox
' Configure the dialog box
dlg.Owner = Me
dlg.DocumentMargin = Me.documentTextBox.Margin
' Open the dialog box modally
dlg.ShowDialog()
...
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
namespace SDKSample
{
public partial class MainWindow : Window
{
...
void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
MarginsDialogBox dlg = new MarginsDialogBox();
// Configure the dialog box
dlg.Owner = this;
dlg.DocumentMargin = this.documentTextBox.Margin;
// Open the dialog box modally
dlg.ShowDialog();
...
}
...
}
}
In questo punto del codice, le informazioni predefinite (i margini correnti) vengono passate alla finestra di dialogo. Viene inoltre impostata la proprietà Window.Owner con un riferimento alla finestra da cui viene visualizzata la finestra di dialogo. In generale, è sempre opportuno impostare il proprietario di una finestra di dialogo per fornire i comportamenti correlati allo stato della finestra comuni a tutte le finestre di dialogo. Per ulteriori informazioni, vedere Cenni preliminari sulle finestre WPF.
Nota |
---|
È necessario fornire un proprietario per supportare l'automazione dell'user interface (UI) per le finestre di dialogo. Vedere Cenni preliminari su automazione interfaccia utente. |
Dopo essere stata configurata, la finestra di dialogo viene visualizzata come modale chiamando il metodo ShowDialog.
Convalida di dati forniti dall'utente
Quando viene aperta una finestra di dialogo e l'utente fornisce i dati necessari, la finestra di dialogo deve garantire che i dati forniti siano validi per i motivi riportati di seguito:
Da un punto di vista della sicurezza, tutti gli input devono essere convalidati.
Da un punto di vista specifico del dominio, la convalida dei dati impedisce l'elaborazione di dati errati da parte del codice, che potrebbe potenzialmente generare eccezioni.
Da un punto di vista dell'esperienza utente, una finestra di dialogo può aiutare l'utente mostrandogli quali dati immessi non sono validi.
Da un punto di vista delle prestazioni, la convalida dei dati in un'applicazione a più livelli può ridurre il numero di sequenze di andata e ritorno tra il client e i livelli dell'applicazione, in particolare se l'applicazione è composta da servizi Web o database basati su server.
Per convalidare un controllo associato in WPF, è necessario definire una regola di convalida e abbinarla all'associazione. Una regola di convalida è una classe personalizzata che deriva da ValidationRule. Nell'esempio riportato di seguito viene illustrata una regola di convalida, MarginValidationRule, che consente di controllare che un valore associato sia Double e compreso in un intervallo specificato.
Imports System.Globalization
Imports System.Windows.Controls
Namespace SDKSample
Public Class MarginValidationRule
Inherits ValidationRule
Private _maxMargin As Double
Private _minMargin As Double
Public Property MaxMargin() As Double
Get
Return Me._maxMargin
End Get
Set(ByVal value As Double)
Me._maxMargin = value
End Set
End Property
Public Property MinMargin() As Double
Get
Return Me._minMargin
End Get
Set(ByVal value As Double)
Me._minMargin = value
End Set
End Property
Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As CultureInfo) As ValidationResult
Dim margin As Double
' Is a number?
If Not Double.TryParse(CStr(value), margin) Then
Return New ValidationResult(False, "Not a number.")
End If
' Is in range?
If ((margin < Me.MinMargin) OrElse (margin > Me.MaxMargin)) Then
Dim msg As String = String.Format("Margin must be between {0} and {1}.", Me.MinMargin, Me.MaxMargin)
Return New ValidationResult(False, msg)
End If
' Number is valid
Return New ValidationResult(True, Nothing)
End Function
End Class
End Namespace
using System.Globalization;
using System.Windows.Controls;
namespace SDKSample
{
public class MarginValidationRule : ValidationRule
{
double minMargin;
double maxMargin;
public double MinMargin
{
get { return this.minMargin; }
set { this.minMargin = value; }
}
public double MaxMargin
{
get { return this.maxMargin; }
set { this.maxMargin = value; }
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double margin;
// Is a number?
if (!double.TryParse((string)value, out margin))
{
return new ValidationResult(false, "Not a number.");
}
// Is in range?
if ((margin < this.minMargin) || (margin > this.maxMargin))
{
string msg = string.Format("Margin must be between {0} and {1}.", this.minMargin, this.maxMargin);
return new ValidationResult(false, msg);
}
// Number is valid
return new ValidationResult(true, null);
}
}
}
In questo codice, la logica di convalida di una regola viene implementata eseguendo l'override del metodo Validate che convalida i dati e restituisce un oggetto ValidationResult appropriato.
Per abbinare la regola di convalida al controllo associato, utilizzare il markup riportato di seguito.
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarginsDialogBox"
xmlns:local="clr-namespace:SDKSample"
Title="Margins"
Height="190"
Width="300"
MinHeight="10"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
<Grid>
...
<Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
<TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
<TextBox.Text>
<Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
...
</Window>
Dopo essere stata abbinata, la regola di convalida verrà automaticamente applicata da WPF nel momento in cui verranno immessi dati nel controllo associato. Se un controllo contiene dati non validi, in WPF verrà visualizzato un bordo rosso intorno al controllo non valido, come illustrato di seguito.
In WPF l'utente non rimane bloccato sul controllo non valido finché non vengono immessi dati validi. In questo modo, sarà libero di spostarsi tra i controlli della finestra di dialogo anche se i dati immessi non sono validi. Ciò significa, tuttavia, che un utente può immettere dati non validi e premere il pulsante OK. Per questo motivo, il codice deve anche prevedere la convalida di tutti i controlli di una finestra di dialogo quando viene premuto il pulsante OK gestendo l'evento Click.
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
...
Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Don't accept the dialog box if there is invalid data
If Not Me.IsValid(Me) Then Return
...
End Sub
' Validate all dependency objects in a window
Private Function IsValid(ByVal node As DependencyObject) As Boolean
' Check if dependency object was passed and if dependency object is valid.
' NOTE: Validation.GetHasError works for controls that have validation rules attached
If ((Not node Is Nothing) AndAlso Validation.GetHasError(node)) Then
' If the dependency object is invalid, and it can receive the focus,
' set the focus
If TypeOf node Is IInputElement Then
Keyboard.Focus(DirectCast(node, IInputElement))
End If
Return False
End If
' If this dependency object is valid, check all child dependency objects
Dim subnode As Object
For Each subnode In LogicalTreeHelper.GetChildren(node)
If (TypeOf subnode Is DependencyObject AndAlso Not Me.IsValid(DirectCast(subnode, DependencyObject))) Then
' If a child dependency object is invalid, return false immediately,
' otherwise keep checking
Return False
End If
Next
' All dependency objects are valid
Return True
End Function
End Class
End Namespace
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
...
void okButton_Click(object sender, RoutedEventArgs e)
{
// Don't accept the dialog box if there is invalid data
if (!IsValid(this)) return;
...
}
// Validate all dependency objects in a window
bool IsValid(DependencyObject node)
{
// Check if dependency object was passed
if (node != null)
{
// Check if dependency object is valid.
// NOTE: Validation.GetHasError works for controls that have validation rules attached
bool isValid = !Validation.GetHasError(node);
if (!isValid)
{
// If the dependency object is invalid, and it can receive the focus,
// set the focus
if (node is IInputElement) Keyboard.Focus((IInputElement)node);
return false;
}
}
// If this dependency object is valid, check all child dependency objects
foreach (object subnode in LogicalTreeHelper.GetChildren(node))
{
if (subnode is DependencyObject)
{
// If a child dependency object is invalid, return false immediately,
// otherwise keep checking
if (IsValid((DependencyObject)subnode) == false) return false;
}
}
// All dependency objects are valid
return true;
}
}
}
Nel codice vengono enumerati tutti gli oggetti dipendenza di una finestra e, se ne vengono rilevati di non validi (come restituito dal metodo GetHasError, il controllo non valido riceve lo stato attivo, il metodo IsValid restituisce falsee la finestra viene considerata non valida.
Dopo essere stata ritenuta valida, la finestra di dialogo può essere chiusa. Questo processo deve inoltre prevedere la restituzione di un risultato alla funzione chiamante.
Impostazione del risultato di una finestra di dialogo modale
L'apertura di una finestra di dialogo tramite il metodo ShowDialog è sostanzialmente equivalente alla chiamata a un metodo: il codice che ha aperto la finestra di dialogo tramite il metodo ShowDialog attende la restituzione di un risultato da parte del metodo ShowDialog. Quando il metodo ShowDialog restituisce un risultato, il codice che lo ha chiamato deve decidere se continuare o arrestare l'elaborazione, a seconda che sia stato premuto il pulsante OK o il pulsante Annulla. Per facilitare questa decisione, la finestra di dialogo deve restituire la scelta dell'utente come un valore Boolean restituito dal metodo ShowDialog.
Quando l'utente fa clic sul pulsante OK, il metodo ShowDialog deve restituire true. A tale scopo, impostare la proprietà DialogResult della finestra di dialogo quando viene fatto clic sul pulsante OK.
Si noti che l'impostazione della proprietà DialogResult comporta la chiusura automatica della finestra, in seguito alla quale non è più necessario chiamare in modo esplicito il metodo Close.
Quando viene fatto clic sul pulsante Annulla, il metodo ShowDialog dovrebbe restituire false, risultato che richiede l'impostazione della proprietà DialogResult.
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
...
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Dialog box canceled
Me.DialogResult = False
End Sub
...
End Class
End Namespace
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
...
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
...
}
}
Quando la proprietà IsCancel di un pulsante viene impostata su true e l'utente preme il pulsante Annulla o il tasto ESC, la proprietà DialogResult viene impostata automaticamente su false. Con il markup riportato di seguito si ottiene lo stesso effetto del codice precedente, senza la necessità di gestire l'evento Click.
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
Una finestra di dialogo restituisce automaticamente false quando l'utente preme il pulsante Chiudi nella barra del titolo o sceglie la voce di menu Chiudi dal menu di sistema.
Elaborazione di dati restituiti da una finestra di dialogo modale
Quando la proprietà DialogResult viene impostata da una finestra di dialogo, la funzione che ne ha comportato l'apertura può ottenere il risultato della finestra di dialogo controllando la proprietà DialogResult quando il metodo ShowDialog restituisce un risultato.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
...
Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
...
' Process data entered by user if dialog box is accepted
If (dlg.DialogResult.GetValueOrDefault = True) Then
Me.documentTextBox.Margin = dlg.DocumentMargin
End If
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
namespace SDKSample
{
public partial class MainWindow : Window
{
...
void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
{
...
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.Margin = dlg.DocumentMargin;
}
}
...
}
}
Se il risultato della finestra di dialogo è true, la funzione utilizza tale risultato con un'indicazione per recuperare ed elaborare i dati forniti dall'utente.
Nota |
---|
Dopo la restituzione di un risultato da parte del metodo ShowDialog, una finestra di dialogo non può più essere riaperta.È invece necessario creare una nuova istanza. |
Se il risultato della finestra di dialogo è false, l'elaborazione della funzione viene terminata in modo appropriato.
Creazione di una finestra di dialogo non modale personalizzata
Una finestra di dialogo non modale, ad esempio la finestra di dialogo Trova illustrata di seguito, presenta sostanzialmente lo stesso aspetto di una finestra di dialogo modale.
Il comportamento è invece leggermente diverso, come descritto nelle sezioni riportate di seguito.
Apertura di una finestra di dialogo non modale
Una finestra di dialogo non modale viene aperta chiamando il metodo Show.
<!--Main Window-->
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
...
Private Sub editFindMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim dlg As New FindDialogBox(Me.documentTextBox)
dlg.Owner = Me
AddHandler dlg.TextFound, New TextFoundEventHandler(AddressOf Me.dlg_TextFound)
dlg.Show()
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
namespace SDKSample
{
public partial class MainWindow : Window
{
...
void editFindMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
FindDialogBox dlg = new FindDialogBox(this.documentTextBox);
// Configure the dialog box
dlg.Owner = this;
dlg.TextFound += new TextFoundEventHandler(dlg_TextFound);
// Open the dialog box modally
dlg.Show();
}
...
}
}
A differenza di ShowDialog, il metodo Show restituisce immediatamente un risultato. Di conseguenza, la finestra chiamante non può stabilire quando la finestra di dialogo non modale viene chiusa e pertanto non sa quando verificare il risultato della finestra di dialogo o quando ottenere dati dalla finestra di dialogo per continuare l'elaborazione. La finestra di dialogo deve quindi disporre di un modo alternativo per restituire dati alla finestra chiamante.
Elaborazione di dati restituiti da una finestra di dialogo non modale
In questo esempio, la FindDialogBox potrebbe restituire uno o più risultati di ricerca alla finestra principale, a seconda del testo cercato senza una frequenza specifica. Analogamente a una finestra di dialogo modale, una finestra di dialogo non modale può restituire risultati utilizzando le proprietà. La finestra proprietaria della finestra di dialogo deve, tuttavia, sapere quando controllare tali proprietà. A tal fine, la finestra di dialogo dovrebbe implementare un evento che viene generato ogni volta che viene trovato il testo. FindDialogBox implementa a questo scopo TextFoundEvent, che innanzitutto richiede un delegato.
Namespace SDKSample
Public Delegate Sub TextFoundEventHandler(ByVal sender As Object, ByVal e As EventArgs)
End Namespace
using System;
namespace SDKSample
{
public delegate void TextFoundEventHandler(object sender, EventArgs e);
}
Tramite il delegato TextFoundEventHandler, la finestra di dialogo FindDialogBox implementa TextFoundEvent.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
Public Event TextFound As TextFoundEventHandler
Protected Overridable Sub OnTextFound()
RaiseEvent TextFound(Me, EventArgs.Empty)
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
namespace SDKSample
{
public partial class FindDialogBox : Window
{
public event TextFoundEventHandler TextFound;
protected virtual void OnTextFound()
{
TextFoundEventHandler textFound = this.TextFound;
if (textFound != null) textFound(this, EventArgs.Empty);
}
...
}
}
Di conseguenza, Find può generare l'evento quando viene trovato un risultato di ricerca.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
...
Private Sub findNextButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
...
Me.Index = match.Index
Me.Length = match.Length
RaiseEvent TextFound(Me, EventArgs.Empty)
...
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
namespace SDKSample
{
public partial class FindDialogBox : Window
{
...
void findNextButton_Click(object sender, RoutedEventArgs e)
{
...
// Text found
this.index = match.Index;
this.length = match.Length;
OnTextFound();
...
}
...
}
}
La finestra proprietaria deve quindi effettuare la registrazione e gestire questo evento.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
...
Private Sub dlg_TextFound(ByVal sender As Object, ByVal e As EventArgs)
Dim dlg As FindDialogBox = DirectCast(sender, FindDialogBox)
Me.documentTextBox.Select(dlg.Index, dlg.Length)
Me.documentTextBox.Focus()
End Sub
End Class
End Namespace
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
namespace SDKSample
{
public partial class MainWindow : Window
{
...
void dlg_TextFound(object sender, EventArgs e)
{
// Get the find dialog box that raised the event
FindDialogBox dlg = (FindDialogBox)sender;
// Get find results and select found text
this.documentTextBox.Select(dlg.Index, dlg.Length);
this.documentTextBox.Focus();
}
}
}
Chiusura di una finestra di dialogo non modale
Poiché non è necessario impostare DialogResult, una finestra di dialogo non modale può essere chiusa utilizzando i meccanismi forniti dal sistema, tra cui:
Pulsante Chiudi nella barra del titolo.
ALT + F4.
Voce Chiudi del menu di sistema.
In alternativa, è possibile chiamare il metodo Close quando viene fatto clic sul pulsante Chiudi.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
...
Private Sub closeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
MyBase.Close()
End Sub
End Class
End Namespace
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
namespace SDKSample
{
public partial class FindDialogBox : Window
{
...
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close dialog box
this.Close();
}
}
}
Vedere anche
Concetti
Cenni preliminari sul controllo Popup