Inizializzazione di elementi oggetto non presenti in una struttura ad albero di oggetti
Alcuni aspetti dell'inizializzazione Windows Presentation Foundation (WPF) vengono rinviati ai processi che generalmente si basano sull'elemento connesso all'albero logico o alla struttura ad albero visuale. In questo argomento vengono descritti i passaggi necessari per inizializzare un elemento non connesso a una delle strutture ad albero.
Nel presente argomento sono contenute le seguenti sezioni.
- Elementi e albero logico
- Argomenti correlati
Elementi e albero logico
Quando si crea un'istanza di una classe Windows Presentation Foundation (WPF) all'interno del codice, è necessario tenere presente che molti aspetti dell'inizializzazione dell'oggetto per una classe Windows Presentation Foundation (WPF) non fanno deliberatamente parte del codice che viene eseguito quando si chiama il costruttore di classi. In modo particolare per una classe di controllo, la maggior parte delle rappresentazioni visive di quel controllo non viene definita dal costruttore, ma dal modello del controllo. Sebbene provenga potenzialmente da diverse origini, nella maggior parte dei casi il modello viene ottenuto dagli stili dei temi. I modelli sono effettivamente un'associazione tardiva; il modello necessario non viene associato al controllo in questione finché il controllo non è pronto per il layout e quest'ultima situazione non si verifica finché il controllo non viene associato a un albero logico che si connette a una superficie di rendering nella radice. È tale elemento a livello radice che avvia il rendering di tutti i relativi elementi figlio definiti nell'albero logico.
Anche la struttura ad albero visuale partecipa a questo processo. Non viene creata un'istanza completa per gli elementi che fanno parte della struttura ad albero visuale tramite i modelli finché questi non vengono connessi.
Le conseguenze di questo comportamento sono la necessità di passaggi aggiuntivi per alcune operazioni basate sulle caratteristiche visive completate di un elemento. Un esempio è rappresentato dal tentativo di ottenere le caratteristiche visive di una classe costruita, ma non ancora associata a una struttura ad albero. Ad esempio, se si desidera chiamare il metodo Render in un oggetto RenderTargetBitmap e se l'elemento visivo che si sta passando è un elemento non connesso a una struttura ad albero, tale elemento non viene completato in modo visivo finché non vengono terminati ulteriori passaggi di inizializzazione.
Utilizzo di BeginInit e EndInit per inizializzare l'elemento
Diverse classi di WPF implementano l'interfaccia ISupportInitialize. Per indicare un'area del codice contenente passaggi di inizializzazione (ad esempio l'impostazione di valori della proprietà che influiscono sul rendering), vengono utilizzati i metodi BeginInit e EndInit dell'interfaccia. Dopo aver chiamato il metodo EndInit nella sequenza, il sistema di layout può elaborare l'elemento e iniziare a cercare uno stile implicito.
Se l'elemento per cui si stanno impostando le proprietà è una classe derivata FrameworkElement o FrameworkContentElement, è possibile chiamare le versioni della classe di BeginInit e EndInit, invece di eseguire il cast sull'oggetto ISupportInitialize.
Codice di esempio
L'esempio seguente è un codice di esempio per un'applicazione console che utilizza le APIs di rendering e XamlReader.Load(Stream) di un file XAML separato per illustrare il posizionamento corretto di BeginInit e di EndInit intorno ad altre chiamate API che regolano le proprietà che influiscono sul rendering.
Nell'esempio seguente viene illustrata solo la funzione principale. Le funzioni Rasterize e Save (non mostrate) sono funzioni di utilità che gestiscono l'elaborazione di immagini e l'I/O.
<STAThread>
Shared Sub Main(ByVal args() As String)
Dim e As UIElement
Dim _file As String = Directory.GetCurrentDirectory() & "\starting.xaml"
Using stream As Stream = File.Open(_file, FileMode.Open)
' loading files from current directory, project settings take care of copying the file
Dim pc As New ParserContext()
pc.BaseUri = New Uri(_file, UriKind.Absolute)
e = CType(XamlReader.Load(stream, pc), UIElement)
End Using
Dim paperSize As New Size(8.5 * 96, 11 * 96)
e.Measure(paperSize)
e.Arrange(New Rect(paperSize))
e.UpdateLayout()
'
' * Render effect at normal dpi, indicator is the original RED rectangle
'
Dim image1 As RenderTargetBitmap = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96)
Save(image1, "render1.png")
Dim b As New Button()
b.BeginInit()
b.Background = Brushes.Blue
b.Height = 200
b.Width = b.Height
b.EndInit()
b.Measure(paperSize)
b.Arrange(New Rect(paperSize))
b.UpdateLayout()
' now render the altered version, with the element built up and initialized
Dim image2 As RenderTargetBitmap = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96)
Save(image2, "render2.png")
End Sub
[STAThread]
static void Main(string[] args)
{
UIElement e;
string file = Directory.GetCurrentDirectory() + "\\starting.xaml";
using (Stream stream = File.Open(file, FileMode.Open))
{
// loading files from current directory, project settings take care of copying the file
ParserContext pc = new ParserContext();
pc.BaseUri = new Uri(file, UriKind.Absolute);
e = (UIElement)XamlReader.Load(stream, pc);
}
Size paperSize = new Size(8.5 * 96, 11 * 96);
e.Measure(paperSize);
e.Arrange(new Rect(paperSize));
e.UpdateLayout();
/*
* Render effect at normal dpi, indicator is the original RED rectangle
*/
RenderTargetBitmap image1 = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96);
Save(image1, "render1.png");
Button b = new Button();
b.BeginInit();
b.Background = Brushes.Blue;
b.Width = b.Height = 200;
b.EndInit();
b.Measure(paperSize);
b.Arrange(new Rect(paperSize));
b.UpdateLayout();
// now render the altered version, with the element built up and initialized
RenderTargetBitmap image2 = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96);
Save(image2, "render2.png");
}