访问内容模板中控件的方法

发布于 2024-12-27 01:40:28 字数 5888 浏览 0 评论 0原文

对于 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 类型的对象添加到列表中,将列表设置为选项卡控件的 ItemsSource 属性,一切都完美运行:我得到两个以“我的名字”和“您的名字”作为标题的选项卡,描述显示在正确的位置,按钮正确地打开或关闭粗体。

我的问题是,如何在选项卡控件外部添加一个按钮,该按钮可以调用位于所选项目的内容模板中的 MyControl 对象的 MyControl.ToggleBold 方法:

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

...

I知道我可以通过调用 tabItems.SelectedContentTemplate 来访问数据模板,但据我所知,我无法访问模板内的控件(而且我认为我也不应该这样做)。有 FindName 方法,但我不知道作为 templatedParent 参数传递。

任何帮助将不胜感激。

Relative WPF new-comer, this will probably have a simple solution (I hope!). I have a class with two properties:

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

I have a user control which has a textblock and a button: the textblock displays text (obviously) and the button is used to either bold or unbold the text of the text block:

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

In my MainWindow I have a tab control which has an item template (to display MyClass.Name in the header of each tab) and a content template. The content template contains one of my above controls and MyClass.Description is bound to 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;
    }
}

When the program runs I add two objects of type MyClass to a List, set the list to the ItemsSource property of the tab control and it all works perfectly: I get two tabs with "My Name" and "Your Name" as the headers, the description is shown in the correct place and the button turns the bold on or off correctly.

My question is this, how do I add a button OUTSIDE of the tab control which could call the MyControl.ToggleBold method of the MyControl object which is in the content template of the selected item:

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

...

I know I can access the data template by calling tabItems.SelectedContentTemplate but as far as I can tell I cannot access controls within the template (and I don't think I should be doing that either). There is the FindName method but I don't know pass as the templatedParent parameter.

Any help would be hugely appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

折戟 2025-01-03 01:40:28

您可以导航 VisualTree 来查找您要查找的控件。

例如,我使用一组 自定义 VisualTreeHelpers< /code>这将允许我调用这样的东西:

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

You can navigate the VisualTree to find the control you're looking for.

For example, I use a set of custom VisualTreeHelpers which would allow me to call something like this:

var myControl = VisualTreeHelpers.FindChild<MyControl>(myTabControl);
if (myControl != null)
    myControl.ToggleBold();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文