2013-10-01 3 views
19

Это XAML:Доступ к управлению внутри 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> 

Я Тринг, чтобы получить доступ к TextBlock с именем textBlock2.
Я попытался переопределить OnApplyTemplate, но получил значение null.

Я пробовал:

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

Я подозреваю, что ваша кнопка еще не загружена (отображается в пользовательском интерфейсе). Ваш код вернет null только в том случае, если шаблон применяется к кнопке. –

+0

Также 'gridInTemplate' является нулевым, так как вы не указали' x: Name' на свою Grid в объявлении xaml. –

+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

Я получаю следующее исключение: «Указанный индекс находится за пределами допустимого диапазона, или дочерний элемент в индексе имеет значение null. Не вызывайте этот метод, если VisualChildrenCount возвращает ноль, что указывает на то, что у Visual нет дочерних элементов. – toy4fun

+0

Такая же проблема здесь, добавлена ​​баунти – DaveO

+0

'var ct0 = btnWedding.Template.FindName (" textBlock2 ", btnWedding);' отлично работает для меня ... можете ли вы поделиться тем, где именно в вашем коде вы пытаетесь получить текстовый блок? – Nitin

4

Ваш код является правильным, но, вероятно, не в нужном месте ... FindName будет работать только после того, как шаблон был применен. Как правило, вы используете его, когда вы переопределяете OnApplyTemplate в пользовательском элементе управления. Поскольку вы не создаете настраиваемый элемент управления, вы можете сделать это в событии Loaded кнопки.

18

Если у вас есть overriden 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

Если ваш пример Microsoft пример, то я предлагаю вам прочитать ее еще раз. Возможно, вы что-то пропустили.

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

Резюмируя - Используйте GetTemplateChild() при авторизации пользовательского элемента управления, например, OnApplyTemplate и использовать Template.FindName в других ситуациях.

+0

Это помогло мне. Переопределение «OnApplyTemplate» (вместо «OnTemplateChange») заставило его работать. – Crypt32

1

Метод «FrameworkElement.FindName (имя строки)» использует указатель макета, в котором кнопка/элемент управления используется для разрешения имен. Короче говоря, вы можете использовать это, чтобы найти детей в панели сетки или стека в макете приложения.Но вы не можете использовать то же самое, чтобы найти дочерние элементы элемента управления, который вы использовали в макете вашего приложения (поскольку имена шаблонных chidren находятся в другом объеме)

Одним из способов, с помощью которых вы можете получить детей в своей ситуации, является наследование кнопка. Поскольку вы не будете изменять какое-либо другое свойство или поведение кнопки, новая кнопка будет работать как обычная. Практически я никогда не использовал такой метод доступа к темплатированным детям, поскольку мне никогда не приходилось использовать их вне сферы действия элемента управления.

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