2013-10-01 28 views
19

内部控制这是XAML:访问一个控件模板

<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> 

我特林可以访问一个名为textBlock2 TextBlock的。
我试过重写OnApplyTemplate,但得到空值。

我已经试过:

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"); 

的gridInTemplate为空(从MSDN获取的样品)。
当然,ct#全为空。

我在这里错过了什么?

+2

我怀疑你的按钮没有'加载(在UI上呈现)'呢。只有在模板应用于按钮时,您的代码才会返回null。 –

+0

由于您尚未在xaml声明中为您的网格指定'x:Name',因此'gridInTemplate'为null。 –

+1

我碰到类似的问题,不得不调用'UpdateLayout'来解决@RohitVats提到的问题。 – Chris

回答

1

如果你能得到的网格控件,然后尝试使用下面的代码

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

我的错误,网格为空,虽然我拿了来自MSDN示例的代码。问题相应更新。 – toy4fun

2

可以使用VisualTreeHelper迭代按钮的视觉树得到任何孩子。你可以使用这个基本的通用功能,让它

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); 
} 

,你可以使用它像

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

我收到以下异常:'指定的索引超出范围或索引处的子项为空。如果VisualChildrenCount返回0,则不要调用此方法,这表示Visual没有子项.' – toy4fun

+0

同样的问题在这里,添加了一个赏金 – DaveO

+0

'var ct0 = btnWedding.Template.FindName(“textBlock2”,btnWedding);'对我来说工作正常...你能分享你的代码中你想要获得文本块的位置吗? – Nitin

4

你的代码是正确的,但可能不会在正确的地方... FindName后,才工作模板已被应用。通常,您在自定义控件中覆盖OnApplyTemplate时使用它。由于您没有创建自定义控件,因此可以在按钮的Loaded事件中执行此操作。

18

如果您已覆盖OnApplyTemplate,则不要使用FindResource()或Template.FindName()或VisualTreeHelper的任何黑客行为。只需使用this.GetTemplateChild("textBlock2");

WPF中的模板具有独立的名称范围。这是因为模板被重用,并且当一个控件的多个实例每个实例化其模板时,模板中定义的任何名称都不能保持唯一。调用GetTemplateChild方法以返回对实例化后来自模板的对象的引用。您不能使用FrameworkElement.FindName方法从模板中查找项目,因为FrameworkElement.FindName在更一般的范围内起作用,并且在应用ControlTemplate类本身和实例化模板之间没有连接。

检查此链接了:

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

如果你的例子是微软的例子那么我建议你读一遍。你可能跳过了一些东西。例如创作自定义控制时使用GetTemplateChild() -

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

综上所述OnApplyTemplate,并在其他情况下使用Template.FindName。

+0

这对我有帮助。通过重写'OnApplyTemplate'(而不是'OnTemplateChange')使其工作。 – Crypt32

1

“FrameworkElement.FindName(string name)”方法使用按钮/控件用于解析名称的布局的名称范围。总之,您可以使用它在应用程序布局中的网格或堆栈面板中查找子节点。但是你不能用同样的方法找到你在应用程序布局中使用的控件的子对象(因为模板子对象名称在不同的范围内)

你可以让你的情况下的子对象继承按钮。由于您不会修改按钮的任何其他属性或行为,因此新按钮将像普通按钮一样工作。实际上,我从来没有使用过这种访问模板儿童的方法,因为我从来没有必要在控件类的范围之外使用它们。

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

请尝试以下代码。这将返回模板元素。

this.GetTemplateChild("ControlName");