如何在自定义控件中访问控件模板中的控件

本文关键字:控件 访问 自定义控件 | 更新日期: 2023-09-27 18:05:33

我正在开发一个WPF自定义控件

<ResourceDictionary xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MultiSelectComboBox">
    <Style TargetType="{x:Type local:MultiSelectComboBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MultiSelectComboBox}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions >
                            <telerik:RadComboBox x:Name="PART_ComboBox"
                                                 Grid.Column="0"
                                                 ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}" >
                               <telerik:RadComboBox.Template>
                                    <ControlTemplate>
                                        <TextBlock x:Name="PART_ComboText"/> 
                                    </ControlTemplate>
                                </telerik:RadComboBox.Template>
                                <telerik:RadComboBox.ItemTemplate> 
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <CheckBox x:Name="PART_ItemCheckBox"/>
                                            <TextBlock x:Name="PART_ItemText"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </telerik:RadComboBox.ItemTemplate>
                            </telerik:RadComboBox>
                            <CheckBox Grid.Column="1" x:Name="PART_SelectAllCheckBox" VerticalAlignment="Center" IsChecked="{TemplateBinding IsAllSelected}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

我想访问PART_ComboText

我可以使用GetTempalteChild方法访问那里定义的控件

part_comboBox = GetTemplateChild("PART_ComboBox") as RadComboBox;

但是我无法访问控制模板内的控件。举个例子它在控制模板中无法访问。我知道我们无法从后台代码访问控制模板。

我试过这个方法。

part_comboBox = GetTemplateChild("PART_ComboBox") as RadComboBox;
var comboBoxTemplate = part_comboBox.Template;
part_comboText = (TextBlock) comboBoxTemplate.FindName("PART_ComboText", part_comboBox);

如何在自定义控件中访问控件模板中的控件

这可能是因为当您试图找到TextBlock时,RadComboBox没有完全加载。

检查它的IsLoaded属性,知道它是否准备好了。如果不是,您将不得不推迟代码的执行,直到它的Loaded事件被引发。

part_comboBox = GetTemplateChild("PART_ComboBox") as RadComboBox;
if (part_comboBox.IsLoaded)
{
    part_comboText = part_comboBox.FindName("PART_ComboText");
    DoStuffWithComboText(part_comboText);
}
else
{
    part_comboBox.Loaded = new RoutedEventHandler((o, e) =>
    {
        part_comboText = part_comboBox.FindName("PART_ComboText");
        // Or... part_comboText = part_comboBox.Template.FindName("PART_ComboText", part_comboBox); ... can't remember which one was correct in this case
        DoStuffWithComboText(part_comboText);
    }
}

使用OnApplyTemplate()来操作子控件,并在静态方法PropertyChangedCallback中调用它:

public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        if (Template != null)
        {
            Image partImage = Template.FindName("PART_Image", this) as Image;
            if (partImage != null)
            {
                if (String.IsNullOrEmpty(Picture))
                {
                    partImage.Visibility = Visibility.Hidden;
                    partImage.Width = 0;
                }
                else
                {
                    partImage.Visibility = Visibility.Visible;
                    partImage.Width = 16;
                }
            }
        }
    }
public string Picture
    {
        get => (string)GetValue(PictureProperty);
        set => SetValue(PictureProperty, value);
    }
    private static void OnPictureChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ButtonUI control = d as ButtonUI;
        control.OnApplyTemplate();
    }

主题的通用是简单的:

<Style TargetType="{x:Type local:ButtonUI}" BasedOn="{StaticResource {x:Type Button}}">
        <Setter Property="Height" Value="24" />
        <Setter Property="Width" Value="100" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ButtonUI}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <WrapPanel VerticalAlignment="Center" HorizontalAlignment="Center">
                            <Image Name="PART_Image" Source="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:ButtonUI}},Path=Picture}" Height="16" Width="16" Margin="2,0,2,0" />
                            <TextBlock Name="PART_Caption" Text="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:ButtonUI}},Path=Caption}" Margin="2,0,2,0" />
                        </WrapPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>