Risoluzione dei problemi relativi agli errori di caricamento di Progettazione WPF
Aggiornamento: novembre 2007
Progettazione Windows Presentation Foundation (WPF) per Visual Studio include una finestra di progettazione visiva sofisticata ed estensibile che raffigura il codice XAML. Se il file XMAL non viene caricato nella finestra di progettazione, è possibile eseguire diverse operazioni per cercare di identificare il problema. In questo argomento vengono descritti alcuni suggerimenti e tecniche per la risoluzione di problemi relativi ad errori di caricamento di WPF Designer.
![]() |
---|
Molte delle tecniche descritte in questo argomento possono essere applicate anche a Expression Blend. |
Passaggi per la risoluzione dei problemi
I passaggi seguenti consentono di risolvere i problemi relativi ad errori di caricamento di WPF Designer.
Leggere tutti i messaggi di eccezione che vengono ricevuti.
Potrebbe sembrare ovvio, ma se si ottiene un'eccezione, occorre leggerne il messaggio. In alcuni casi, il messaggio aiuta a diagnosticare rapidamente il problema. Per ulteriori informazioni, vedere Debug e interpretazione degli errori in Progettazione WPF.
Determinare se il problema è nell'implementazione.
Compilare ed eseguire l'applicazione per determinare se il problema è il risultato solo dell'implementazione o di un'interazione con WPF Designer. Se si riesce a compilare ed eseguire l'applicazione, è probabile che la causa dell'errore in fase di progettazione sia l'implementazione.
Utilizzare il debugger Visual Studio per accedere al codice in fase di progettazione. Per ulteriori informazioni, vedere Procedura dettagliata: debug di controlli personalizzati WPF in fase di progettazione.
Determinare se il problema è un errore di caricamento.
Se la visualizzazione Progettazione non viene caricata a causa di un'eccezione, è probabile che il problema sia un errore di caricamento. Se in fase di progettazione viene caricato del codice personalizzato e in questa fase si verificano eccezioni o errori di caricamento, vedere la sezione Scrittura di codice per la fase di progettazione in questo argomento. Se si sta lavorando con delle risorse e queste non vengono caricate, vedere la sezione Risorse di controlli utente e controlli personalizzati in fase di progettazione in questo argomento.
Rivedere il codice caricato in fase di progettazione.
Esistono due approcci alla scrittura di codice eseguibile anche in fase di progettazione. Il primo approccio consiste nello scrivere codice difensivo controllando i parametri di input alle classi. Il secondo approccio consiste nel controllare se la modalità di progettazione è attiva chiamando il metodo GetIsInDesignMode. Per ulteriori informazioni, vedere la sezione Scrittura di codice per la fase di progettazione in questo argomento.
Rivedere le altre aree del codice.
Rivedere la sezione Suggerimenti per la programmazione in questo argomento per ottenere alcuni suggerimenti per la programmazione quando si utilizza WPF Designer. Rivedere la sezione Tecniche di programmazione più idonee di questo argomento per le tecniche di scrittura di codice più affidabile.
Se vengono ancora riscontati dei problemi, è possibile visitare il WPF Designer forum on MSDN (informazioni in lingua inglese) per comunicare con altri sviluppatori che utilizzano WPF Designer. Per riportare potenziali problemi o fornire suggerimenti, utilizzare il sito Visual Studio and .NET Framework Feedback (informazioni in lingua inglese).
Scrittura di codice per la fase di progettazione
Assicurarsi che il codice venga eseguito correttamente in fase di progettazione così come in fase di esecuzione. Se il codice viene eseguito correttamente in fase di progettazione, non presupporre che Application.Current sia l'applicazione. Ad esempio, se si sta utilizzando Expression Blend, Current è Expression Blend. In fase di progettazione, MainWindow non è la finestra principale dell'applicazione. Le tipiche operazioni che determinano l'errata esecuzione di un controllo personalizzato in fase di progettazione includono gli elementi seguenti.
Esecuzione del cast di Current alla sottoclasse personalizzata di Application.
Esecuzione del cast di MainWindow alla sottoclasse personalizzata di Window.
Utilizzo del metodo FindResource o del metodo FindName su Current o MainWindow.
Creazione di riferimenti a risorse da Application.Resources. L'istanza di Application in fase di progettazione non è la stessa dell'applicazione e non dispone delle stesse risorse.
Mancato controllo dell'eventuale restituzione di un valore null da parte degli oggetti Application.Current o Application.MainWindow. Se l'oggetto Visual Studio non crea un oggetto applicazione, l'oggetto Application.Current può restituire null.
Mancato controllo dell'eventuale restituzione di un valore null da parte dell'oggetto Assembly.GetEntryAssembly. Per Visual Studio, questo metodo restituisce null.
Esistono due approcci alla scrittura di codice per la fase di progettazione. Il primo approccio consiste nello scrivere codice difensivo controllando i parametri di input alle classi, quali i convertitori di valori. Il secondo approccio consiste nel controllare se la modalità di progettazione è attiva chiamando il metodo GetIsInDesignMode.
La verifica dei parametri di input per alcune implementazioni è necessaria perché l'ambiente di progettazione fornisce per alcuni input tipi differenti da quelli forniti dall'ambiente di runtime.
I selettori di stili e i convertitori di valori richiedono in genere l'uso di uno di questi approcci per essere eseguiti in modo corretto in fase di progettazione.
Convertitori di valori
Le implementazioni di IValueConverter personalizzate devono controllare il valore null e il tipo previsto nel primo parametro del metodo Convert. Nel seguente esempio di codice XAML viene mostrata un'associazione a Application.Current che non viene eseguita correttamente in fase di progettazione se il convertitore di valori non è implementato correttamente.
<ComboBox.IsEnabled>
<MultiBinding Converter="{StaticResource specialFeaturesConverter}">
<Binding Path="CurrentUser.Rating" Source="{x:Static Application.Current}"/>
<Binding Path="CurrentUser.MemberSince" Source="{x:Static Application.Current}"/>
</MultiBinding>
</ComboBox.IsEnabled>
L'associazione genera un'eccezione in fase di progettazione perché Application.Current si riferisce all'applicazione della finestra di progettazione anziché all'applicazione. Per impedire l'eccezione, il convertitore di valori deve controllare i parametri di input o verificare la modalità di progettazione.
Nell'esempio di codice seguente viene illustrato come controllare i parametri di input in un convertitore di valori che restituisce true se due parametri di input soddisfano la particolare regola business.
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Check the values array for correct parameters.
// Designers may send null or unexpected values.
if (values == null || values.Length < 2) return false;
if (!(values[0] is int)) return false;
if (!(values[1] is DateTime)) return false;
int rating = (int)values[0];
DateTime date = (DateTime)values[1];
// If the user has a good rating (10+) and has been a member for
// more than a year, special features are available.
if((rating >= 10) &&
(date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
{
return true;
}
return false;
}
Il secondo approccio alla scrittura di codice per la fase di progettazione consiste nel controllare se la modalità di progettazione è attiva. Nell'esempio di codice seguente viene mostrato un controllo della modalità di progettazione al posto del controllo del parametro mostrato prima.
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
return false;
}
int rating = (int)values[0];
DateTime date = (DateTime)values[1];
// If the user has a good rating (10+) and has been a member for
// more than a year, special features are available.
if((rating >= 10) &&
(date.Date < (DateTime.Now.Date - new TimeSpan(365, 0, 0, 0))))
{
return true;
}
return false;
}
Selettori di stile
Anche i selettori di stile personalizzati devono essere implementati per funzionare in modalità di progettazione. Nel seguente esempio di codice XAML viene mostrato un selettore di modello personalizzato che utilizza Application.MainWindow in fase di esecuzione per determinare quale risorsa viene restituita come DataTemplate. In fase di progettazione questa risorsa potrebbe non essere disponibile, pertanto l'override di SelectTemplate in questa fase restituisce null.
<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}"
ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True"/>
Nell'esempio di codice riportato di seguito viene mostrata l'implementazione del selettore di stile.
public class TaskListDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(
object item,
DependencyObject container)
{
if (item != null && item is Task)
{
Task taskitem = item as Task;
Window window = Application.Current.MainWindow;
// To run in design mode, either test for the correct window class
// or test for design mode.
if (window.GetType() == typeof(Window1))
// Or check for design mode:
//if (!DesignerProperties.GetIsInDesignMode(window))
{
if (taskitem.Priority == 1)
return window.FindResource("importantTaskTemplate") as DataTemplate;
else
return window.FindResource("myTaskTemplate") as DataTemplate;
}
}
return null;
}
}
Risorse di controlli utente e controlli personalizzati in fase di progettazione
Per impostazione predefinita, le risorse di UserControl e di controlli personalizzati che sono disponibili in fase di esecuzione potrebbero non esserlo in fase di progettazione. Quando si aggiungono controlli personalizzati e controlli utente a una Page o una Window nell'area di progettazione, viene creata un'istanza del controllo. Le risorse in App.xaml non sono disponibili alle istanze di UserControl e di controllo personalizzato caricate in una pagina o una finestra.
Per rendere disponibili le risorse in fase di progettazione, inserirle in un dizionario risorse separato e includerlo in App.xaml e nel codice XAML del controllo. Modificare tutti i riferimenti StaticResource in riferimenti DynamicResource. Nell'esempio di codice seguente viene mostrato come condividere un dizionario risorse in modo che le risorse siano disponibili in fase di progettazione.
UserControl1.xaml
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Sintassi di URI di tipo pack
Non è necessario utilizzare riferimenti di risorsa relativi all'applicazione. Nell'esempio di codice seguente viene mostrata la sintassi basata sull'applicazione che potrebbe generare errori in fase di progettazione.
<Image Name="image1" Source="pack://application:,,,/Image1.bmp" />
Tali riferimenti sono relativi all'applicazione anziché alla DLL. L'utilizzo di un riferimento di risorsa relativo all'applicazione in una DLL rende la DLL dipendente dalle risorse dell'applicazione padre. Questo approccio è fragile e non ne viene garantito il funzionamento in fase di progettazione.
Anziché utilizzare riferimenti di risorsa relativi all'applicazione, aggiungere risorse alla DLL e utilizzare riferimenti di risorsa basati su componenti. Per ulteriori informazioni, vedere URI di tipo pack in Windows Presentation Foundation.
Negli esempi di codice seguenti viene mostrata la sintassi basata su componenti, vale a dire l'approccio consigliato.
<Image Name="image1" Source="/TestHostApp;component/Image1.bmp" />
<Image Name="image1" Source="pack://application:,,,/TestHostApp;component/Image1
Suggerimenti per la programmazione
Di seguito vengono indicati alcuni suggerimenti di programmazione per quando si lavora con WPF Designer.
Per caricare un controllo personalizzato in WPF Designer, è necessario fornire metodi get e set di CLR per tutte le proprietà di dipendenza che sono state definite. Per ulteriori informazioni, vedere Proprietà Dependency personalizzate.
Gli strumenti decorativi di tipo ComboBox non sono supportati.
Per utilizzare un controllo Windows Form di terze parti, creare un tipo di UserControl che disponga di un'istanza del controllo del fornitore nell'insieme di Controls. Per ulteriori informazioni, vedere Procedura dettagliata: hosting di un controllo Windows Form di terze parti in un'applicazione WPF.
La fase di progettazione per FlowDocument non è supportata direttamente. Se si desidera utilizzare WPF Designer in un FlowDocumentincorporato, posizionare innanzitutto FlowDocument in un controllo Frame, che è quindi possibile utilizzare in WPF Designer.
Tecniche di programmazione più idonee
Di seguito vengono illustrate alcune tecniche di programmazione ritenute più idonee per la scrittura di codice più affidabile per WPF Designer.
Eseguire sempre il wrapping degli ambiti di modifica in istruzioni using o blocchi try/finally. Se viene generata un'eccezione, la modifica viene interrotta nella chiamata Dispose. Per ulteriori informazioni, vedere ModelEditingScope.
Utilizzare un oggetto ModelEditingScope per spostare un controllo da un contenitore a un altro. Se questa operazione non viene eseguita, verrà generata un'eccezione.
In WPF e WPF Designer, non impostare il valore di una proprietà sul valore predefinito se si intende cancellarlo. Per i valori NaN, quali Height, chiamare il metodo ClearValue anziché assegnare NaN.
Quando si recuperano valori da una proprietà, utilizzare il valore calcolato della proprietà. Questo significa che occorre utilizzare la proprietà ComputedValue anziché il metodo GetCurrentValue di ModelItem. Il metodo GetCurrentValue restituisce associazioni e altre espressioni se sono memorizzate nel codice XAML, pertanto è possibile in alcuni casi ottenere eccezioni di cast.
Vedere anche
Altre risorse
Debug e interpretazione degli errori in Progettazione WPF
Procedure dettagliate relative all'uso di XAML e del codice