2014-10-17 6 views
1

У меня есть текстовый блок внутри ContentTemplate расширителя. Я хочу получить доступ к этому текстовому блоку в моем коде за файлом. Это то, что я пытался до сих порДоступ к дочерним элементам управления расширителя

<Expander x:Name="myExp" Header="Whatever ..."> 
      <Expander.ContentTemplate> 
       <DataTemplate> 
        <TextBlock x:Name="txtWhatever"/> 
       </DataTemplate> 
      </Expander.ContentTemplate> 
</Expander> 

Я пытаюсь найти дочерние элементы расширителя, но следующий метод возвращает нуль, как он не находит ребенок для расширителя.

ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myExp); 


private childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
    { 
     DependencyObject child = VisualTreeHelper.GetChild(obj, i); 
     if (child != null && child is childItem) 
      return (childItem)child; 
     else 
     { 
      childItem childOfChild = FindVisualChild<childItem>(child); 
      if (childOfChild != null) 
       return childOfChild; 
     } 
    } 
    return null; 
} 

Каков правильный способ для этого? Кроме того, у Expander есть шаблон управления, применяемый к нему.

<Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type Expander}"> 
      <Border SnapsToDevicePixels="true" BorderThickness="1,1,1,1" Margin="0,0,0,-2" BorderBrush="{DynamicResource DisabledBorderBrush}" > 
       <DockPanel> 
        <ToggleButton x:Name="HeaderSite" MinHeight="0" MinWidth="0" Style="{DynamicResource ToggleButtonGraphicsStyleLRUHeader}" 
           Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" 
           ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" FontFamily="{TemplateBinding FontFamily}" 
           FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" 
           FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" 
           Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
           Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" 
           IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" DockPanel.Dock="Top" 
           Height="24"/> 
        <ContentPresenter x:Name="ExpandSite" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Focusable="false" Visibility="Collapsed" DockPanel.Dock="Bottom"/> 
       </DockPanel> 
      </Border> 
      <ControlTemplate.Triggers> 
       <Trigger Property="IsExpanded" Value="true"> 
        <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/> 
       </Trigger> 
      </ControlTemplate.Triggers> 
     </ControlTemplate> 
    </Setter.Value> 
</Setter> 

ответ

2

Я пробовал свой код, это почти нормально. Я попытался проверить его, например, кнопку «Сначала», он работает нормально. Однако для Expander это сложнее. Здесь подано 2 сообщения:

  • Убедитесь, что расширитель расширен (IsExpanded = true).
  • Убедитесь, что раскладка обновляется (можно назвать UpdateLayout явно)

Поэтому код должен быть:

yourExpander.IsExpanded = true; 
yourExpander.UpdateLayout(); 
//now use your method 
var textBlock = FindVisualChild<TextBlock>(yourExpander); 

Ваш код может сократить больше, как это:

private childItem FindVisualChild<childItem>(DependencyObject obj) 
           where childItem : DependencyObject 
{ 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
    { 
     DependencyObject child = VisualTreeHelper.GetChild(obj, i); 
     if(child is childItem) return (childItem)child;    
     childItem childOfChild = FindVisualChild<childItem>(child); 
     if (childOfChild != null) return childOfChild;    
    } 
    return null; 
} 

Обратите внимание, что child никогда не будет null. Поскольку GetChildrenCount() уже ограничивает диапазон существующих детей, поэтому child должен существовать с указанным индексом i.

+0

Я попытался с помощью кода, но я все еще получаю нуль, когда я пытаюсь получить доступ к TextBlock. Кроме того, текстовый блок находится внутри ContentTemplate расширителя, поэтому я думаю, что пытаюсь получить к нему доступ непосредственно, как этот var textBlock = FindVisualChild (yourExpander); не прав я думаю. – user3668639

+0

@ user3668639 Я попробовал простую демонстрационную версию и да, у моего Expander также есть «ContentTemplate», внутри которого находится TextBlock (я скопировал именно ваш код XAML). В вашем вопросе вы *** подтвердили ***, что не было никакого ребенка, но на самом деле *** много ***. Вы можете попробовать использовать 'System.Diagnostics.Debug.Print' для печати' child.GetType(). ToString() 'в каждом цикле for и посмотреть результат в окне' Output'. Это означает, что на вашей стороне что-то не так, по крайней мере, связано с ***, как вы его проверяете. –

+0

@ user3668639 Вы сказали, что у вашего Expander также есть 'ControlTemplate'? Поэтому, когда вы запускаете код, *** отображается ваш «TextBlock» ***? если это не показано, это проблема. –

0

Вот некоторые из моих попробовать:

FAILED TRY

Эти два способа, которые MSDN упомянутые, после попытки я только что получил нуль:

How to: Find DataTemplate-Generated Elements

How to: Find ControlTemplate-Generated Elements

.

И ссылка намного ниже упоминания также только что получил нулевой

Access a control from within a DataTemplate with its identifying name

.

Также просто this.FindName("name") только что получил нуль:

https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.findname(v=vs.110).aspx

.

УСПЕХ TRY

Наконец метод King King работает,

В моем случае я хочу найти RichTextBox в DataTemplate из ContentTemplate, поэтому я пишу

yourExpander.IsExpanded = true; 
yourExpander.UpdateLayout(); 
//now use your method 
var richTextBox = FindVisualChild<RichTextBox>(yourExpander); 

(но я найти его работает только после того, как окно будет инициализировано и показано, и когда пользователь вызывает событие, например щелчок мыши, если я помещаю его в конструктор, он получает нуль, возможно, я дам ему еще одну попытку позже

20170328updated: Я считаю, использовать FindVisualChild в конструкторе не может найти ребенок, но если вы используете в Window_OnLoaded кажется можно найти, может быть, это потому, что в стадии зарядили контролей становится бетон)

Кроме того, я могу проверить, если вы два RichTextBoxes в DataTemplate из ControlTemplate, таким образом, может получить только первый,

так что, я думаю, что способ изменить FindVisualChild к FindRichTextBox, так что вы можете найти RichTextBox с определенным именем, и до этого вы должны указать имя для контроля, который вы найдете:

(вы можете изменить так же, как ваш тип управления ознакомительной):

public static RichTextBox FindRichTextBox(DependencyObject obj, string name) 
    { 
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(obj, i); 
      //           add the name condition 
      if (child != null && child is RichTextBox && ((RichTextBox)child).Name == name) 
       return (RichTextBox)child; 
      else 
      { 
       RichTextBox childOfChild = FindRichTextBox(child, name); 
       if (childOfChild != null) 
        return childOfChild; 
      } 
     } 
     return null; 
    } 
Смежные вопросы