2013-10-01 14 views
19

Questo è il codice XAML:Accesso a un controllo all'interno di un ControlTemplate

<Page.Resources> 
    <ControlTemplate x:Key="WeddingButtonBigTemplate" TargetType="Button"> 
     <Grid> 
      <Image x:Name="imgNormal" Source="../Images/Married_button2.png"/> 
      <TextBlock x:Name="textBlock2" Style="{StaticResource RegularBlueSpecialBoldText}" LineHeight="28" LineStackingStrategy="BlockLineHeight" HorizontalAlignment="Center" Margin="10,30,10,70" TextWrapping="Wrap" TextAlignment="Center" VerticalAlignment="Stretch" > 
       <Run FontSize="20" Text="The event of"></Run> 
       <Run FontSize="28" Text="{DynamicResource strBride}"></Run> 
      </TextBlock> 
     </Grid> 
    </ControlTemplate> 
</Page.Resources> 

<Grid HorizontalAlignment="Center" VerticalAlignment="Top" Width="1000"> 
    <Button x:Name="btnWedding" HorizontalAlignment="Left" Margin="10,20,0,-49" VerticalAlignment="Top" Template="{StaticResource WeddingButtonBigTemplate}" Foreground="#FF2B4072" Width="380" Click="btnClick" /> 
</Grid> 

sto Tring per ottenere l'accesso al TextBlock nome textBlock2.
Ho provato a sovrascrivere OnApplyTemplate ma ho ottenuto null.

ho provato:

Grid gridInTemplate = (Grid)btnWedding.Template.FindName("grid", btnWedding); 
var ct0 = btnWedding.Template.FindName("textBlock2", btnWedding); 
var ct1 = btnWedding.FindName("textBlock2"); 
var ct2 = btnWedding.FindResource("textBlock2"); 

Il gridInTemplate è nullo (campione prelevato da MSDN).
Il ct # sono tutti nulli, ovviamente.

Cosa mi manca qui?

+2

Sospetto che il tuo pulsante non sia stato ancora "caricato (rendering su interfaccia utente)". Il tuo codice restituirà null solo nel caso in cui il modello venga applicato sul pulsante. –

+0

Anche 'gridInTemplate' è nullo dato che non hai specificato' x: Name' nella griglia in dichiarazione xaml. –

+1

Mi sono imbattuto in un problema simile, ho dovuto chiamare 'UpdateLayout', per risolvere il problema menzionato da @RohitVats. – Chris

risposta

1

Se si riesce a ottenere il controllo della griglia, quindi provare a utilizzare il codice qui sotto

TextBlock textBlock2 = (TextBlock)gridInTemplate.Children[1]; 
+0

Il mio errore, la griglia è nullo, anche se ho preso il codice dall'esempio MSDN. Domanda aggiornata di conseguenza. – toy4fun

2

è possibile utilizzare VisualTreeHelper per iterare l'albero visuale del pulsante per ottenere qualsiasi bambino. È possibile utilizzare questa funzione generica di base per farlo

private static DependencyObject RecursiveVisualChildFinder<T>(DependencyObject rootObject) 
{ 
    var child = VisualTreeHelper.GetChild(rootObject, 0); 
    if (child == null) return null; 

    return child.GetType() == typeof (T) ? child : RecursiveVisualChildFinder<T>(child); 
} 

è possibile utilizzarlo come

TextBlock textblock = RecursiveVisualChildFinder<TextBlock>(btnWedding); 
if(textblock.Name == "textBlock2") 
{// Do your stuff here 
} 
+0

Ricevo la seguente eccezione: 'L'indice specificato non è compreso nell'intervallo o l'indice secondario è null. Non chiamare questo metodo se VisualChildrenCount restituisce zero, indicando che Visual non ha figli. – toy4fun

+0

Lo stesso problema qui, ha aggiunto una taglia – DaveO

+0

'var ct0 = btnWedding.Template.FindName (" textBlock2 ", btnWedding);' funziona bene per me ... puoi condividere dove esattamente nel tuo codice stai cercando di ottenere il blocco di testo? – Nitin

4

Il vostro codice è corretto, ma probabilmente non nel posto giusto ... FindName funzionerà solo dopo la modello è stato applicato. In genere, lo si utilizza quando si esegue l'override di OnApplyTemplate in un controllo personalizzato. Poiché non stai creando un controllo personalizzato, puoi farlo nell'evento Loaded del pulsante.

18

Se hai overridato su OnApplyTemplate, non utilizzare FindResource() o Template.FindName() o qualsiasi hack con VisualTreeHelper. Basta usare this.GetTemplateChild("textBlock2");

I modelli in WPF hanno un namescope autonomo. Questo perché i modelli vengono riutilizzati e qualsiasi nome definito in un modello non può rimanere univoco quando più istanze di un controllo istanziano il proprio modello. Chiamare il metodo GetTemplateChild per restituire i riferimenti agli oggetti che provengono dal modello dopo l'istanza. Non è possibile utilizzare il metodo FrameworkElement.FindName per trovare gli elementi dai modelli perché FrameworkElement.FindName agisce in un ambito più generale e non esiste alcuna connessione tra la classe ControlTemplate e il modello istanziato dopo l'applicazione.

controllare questo link out:

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.gettemplatechild.aspx

Se il vostro esempio è Microsoft esempio, allora vi suggerisco di leggerlo di nuovo. Potresti aver saltato qualcosa.

http://msdn.microsoft.com/en-us/library/bb613586.aspx

Per riassumere - Uso GetTemplateChild() quando si crea controllo personalizzato per esempio OnApplyTemplate e utilizza Template.FindName in altre situazioni.

+0

Questo mi ha aiutato. Sovrascrivendo 'OnApplyTemplate' (invece di 'OnTemplateChange') ha funzionato. – Crypt32

1

Il metodo "FrameworkElement.FindName (nome stringa)" utilizza il namescope del layout in cui viene utilizzato il pulsante/controllo per risolvere i nomi. In breve, puoi usarlo per trovare i bambini in una griglia o in un pannello di stack nel layout dell'applicazione.Ma non puoi usare lo stesso per trovare i figli di un controllo che hai usato nel tuo layout di applicazione (perché i nomi dei chidren basati su modelli sono in un ambito diverso)

Un modo per ottenere i bambini nella tua situazione è ereditare il tasto. Poiché non modificherete altre proprietà o comportamenti del pulsante, il nuovo pulsante funzionerà normalmente. In pratica, non ho mai usato un metodo simile per accedere ai bambini con i modelli poiché non ho mai avuto bisogno di usarli al di fuori dell'ambito della classe del controllo.

public class WeddingButton : Button 
{ 
    public override void OnApplyTemplate() 
    { 
     TextBlock textBlock = this.GetTemplateChild("textBlock2") as TextBlock; 
     base.OnApplyTemplate(); 
    } 
} 

<Page.Resources> 
    <ControlTemplate x:Key="WeddingButtonBigTemplate" TargetType="Button"> 
     <Grid> 
      <Image x:Name="imgNormal" Source="../Images/Married_button2.png"/> 
      <TextBlock x:Name="textBlock2" Style="{StaticResource RegularBlueSpecialBoldText}" LineHeight="28" LineStackingStrategy="BlockLineHeight" HorizontalAlignment="Center" Margin="10,30,10,70" TextWrapping="Wrap" TextAlignment="Center" VerticalAlignment="Stretch" > 
       <Run FontSize="20" Text="The event of"></Run> 
       <Run FontSize="28" Text="{DynamicResource strBride}"></Run> 
      </TextBlock> 
     </Grid> 
    </ControlTemplate> 
</Page.Resources> 

<Grid HorizontalAlignment="Center" VerticalAlignment="Top" Width="1000"> 
    <WeddingButton x:Name="btnWedding" HorizontalAlignment="Left" Margin="10,20,0,-49" VerticalAlignment="Top" Template="{StaticResource WeddingButtonBigTemplate}" Foreground="#FF2B4072" Width="380" Click="btnClick" /> 
</Grid> 
4

Provare il seguente codice. Ciò restituirà l'elemento basato su modello.

this.GetTemplateChild("ControlName");