Доступ к методам элемента управления в шаблоне содержимого - PullRequest
0 голосов
/ 12 января 2012

Относительный новичок в WPF, возможно, это будет простое решение (надеюсь!). У меня есть класс с двумя свойствами:

public class MyClass
{
    public String Name { get; set; }
    public String Description { get; set; }
}

У меня есть пользовательский элемент управления, в котором есть текстовый блок и кнопка: текстовый блок отображает текст (очевидно), а кнопка используется либо для полужирного, либо для полужирного текста текстового блока:

MyControl.xaml:

<UserControl
    x:Class="WpfApplication1.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d" 
    d:DesignHeight="300"
    d:DesignWidth="300"
    xmlns:this="clr-namespace:WpfApplication1">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="48" />
        </Grid.ColumnDefinitions>

        <TextBlock
            x:Name="txtDescription"
            Grid.Column="0"
            Text="{Binding Path=Description, RelativeSource={RelativeSource AncestorType={x:Type this:MyControl}}}" />

        <Button
            x:Name="btnBold"
            Grid.Column="1"
            Content="Bold"
            Click="btnBold_Click" />
    </Grid>
</UserControl>

MyControl.xaml.cs:

public partial class MyControl : UserControl
{
    public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(String), typeof(MyControl));

    public String Description
    {
        get { return GetValue(MyControl.DescriptionProperty) as String; }
        set { SetValue(MyControl.DescriptionProperty, value); }
    }

    public MyControl()
    {
        InitializeComponent();
    }

    private void btnBold_Click(object sender, RoutedEventArgs e)
    {
        ToggleBold();
    }

    public void ToggleBold()
    {
        if (txtDescription.FontWeight == FontWeights.Bold)
        {
            btnBold.Content = "Bold";
            txtDescription.FontWeight = FontWeights.Normal;
        }
        else
        {
            btnBold.Content = "Unbold";
            txtDescription.FontWeight = FontWeights.Bold;
        }
    }
}

В моем главном окне у меня есть элемент управления вкладкой, который имеет шаблон элемента (для отображения MyClass.Name в заголовке каждой вкладки) и шаблон содержимого. Шаблон содержимого содержит один из указанных выше элементов управления, и MyClass.Description привязано к MyControl.Description:

MainWindow.xaml:

<Window
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350"
    Width="525"
    xmlns:this="clr-namespace:WpfApplication1">
    <Grid>
        <TabControl x:Name="tabItems">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
            </TabControl.ItemTemplate>

            <TabControl.ContentTemplate>
                <DataTemplate>
                    <this:MyControl
                        Description="{Binding Description}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        List<MyClass> myClasses = new List<MyClass>();
        myClasses.Add(new MyClass() { Name = "My Name", Description = "My Description" });
        myClasses.Add(new MyClass() { Name = "Your Name", Description = "Your Description" });

        tabItems.ItemsSource = myClasses;
    }
}

Когда программа запускается, я добавляю два объекта типа MyClass в список List, присваиваю список свойству ItemsSource элемента управления вкладками, и все работает отлично: я получаю две вкладки с «My Name» и «Your Name» как заголовки, описание отображается в правильном месте, а кнопка включает или выключает жирный шрифт правильно.

Мой вопрос заключается в следующем: как добавить кнопку ВНЕ элемента управления вкладками, которая могла бы вызвать метод MyControl.ToggleBold объекта MyControl, который находится в шаблоне содержимого выбранного элемента:

MainWindow.xaml:

<Window
    x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350"
    Width="525"
    xmlns:this="clr-namespace:WpfApplication1">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />            
        </Grid.RowDefinitions>

        <TabControl x:Name="tabItems" Grid.Row="0">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
            </TabControl.ItemTemplate>

            <TabControl.ContentTemplate>
                <DataTemplate>
                    <this:MyControl
                        x:Name="myControl"
                        Description="{Binding Description}"/>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>

        <Button Grid.Row="1" Content="Toggle Selected Tab" Click="Button_Click" />
    </Grid>
</Window>

MainWindow.xaml.cs:

...

private void Button_Click(object sender, RoutedEventArgs e)
{
    MyClass myClass = tabItems.SelectedItem as MyClass;
    MyControl myControl;

    ///get the instance of myControl that is contained
    ///in the content template of tabItems for the
    ///myClass item

    myControl.ToggleBold();
}

...

Я знаю, что могу получить доступ к шаблону данных, вызвав tabItems.SelectedContentTemplate, но, насколько я могу судить, я не могу получить доступ к элементам управления в шаблоне (и я не думаю, что мне следует это делать). Существует метод FindName, но я не знаю, передать как параметр templatedParent.

Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 13 января 2012

Вы можете перемещаться по VisualTree, чтобы найти нужный элемент управления.

Например, я использую набор custom VisualTreeHelpers, который позволил бы мне вызвать что-то вроде этого:

var myControl = VisualTreeHelpers.FindChild<MyControl>(myTabControl);
if (myControl != null)
    myControl.ToggleBold();
...