c# - 如何在 WPF 中按名称查找样式触发器嵌入元素?

标签 c# wpf xaml triggers contentcontrol

首先,问题的核心:如果通过样式触发器将元素指定为 ContentControl 的内容,我似乎无法通过名称找到它。

现在,了解更多详细信息:我有一个面板,其布局和功能根据其数据上下文有很大差异,这是错误库中的错误。当该错误为空时,它是一个搜索表单,当它为非空时,它是该错误属性的简单查看器。 XAML 看起来像这样:

<ContentControl DataContext="...">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="Content">
                <Setter.Value>
                    ...
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding}" Value="{x:Null}">
                    <Setter Property="Content">
                        <StackPanel>
                            <TextBox Name="Waldo"/>
                            <Button .../>
                        </StackPanel>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

当用户单击位于文本框旁边的按钮时,我会在后面的代码中收到回调。从那时起,我希望能够访问文本框的各种属性。问题是,Waldo 在哪里? :)

在后面的代码中,我尝试了以下几种变体,但都收效甚微:

this.FindName("Waldo"); // Always returns null

我看到很多关于这个话题的讨论,因为它与 templates 相关但与直接使用触发器设置内容无关。也许是因为我这样做违反了各种最佳实践:)

谢谢!

最佳答案

If an element is assigned as the Content of a ContentControl via a style trigger, I can't seem to find it by name.

如果您需要在触发器发生之前访问 Content,这很可能是不可能的。在这种情况下,最主要的事情是在DataTrigger 发生之后获取访问权。

I am violating all sorts of best practices by doing this

也许这不是在 WPF 中使用 Сontrol 的正确方法,您仍然需要访问动态内容,这些内容以后可以更改。但无论如何,有两种方法可以使用 Сontrol - 就像现在和 MVVM 风格。 MVVM 风格最适合具有不同业务逻辑的大型且不太复杂的应用程序。如果您的情况是为了方便应用,在这种情况下,我认为没有任何问题。除了需要从头开始做一个MVVM风格的项目外,将常规方法和正确的方法结合起来并不是一个好方法。

我创建了一个小示例来演示给定情况下的访问控制。有一个属性对应Content的类型,默认是Init。如果您为此属性分配 null,则会加载动态内容。

这就是我访问 TextBox 的方式:

private void GetAccessToTextBox_Click(object sender, RoutedEventArgs e)
{
    TextBox MyTextBox = null;
    StackPanel panel = MainContentControl.Content as StackPanel;

    foreach (object child in panel.Children)
    {
        if (child is TextBox)
        {
            MyTextBox = child as TextBox;
        }
    }

    if (MyTextBox != null) 
    {
        MyTextBox.Background = Brushes.Gainsboro;
        MyTextBox.Height = 100;
        MyTextBox.Text = "Got access to me!";
    }
}

下面是一个完整的例子:

XAML

<Window x:Class="AccessToElementInContentControl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:AccessToElementInContentControl"
        WindowStartupLocation="CenterScreen"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <this:TestData />
    </Window.DataContext>

    <Window.Resources>
        <Style TargetType="{x:Type ContentControl}">
            <Setter Property="Content">
                <Setter.Value>
                    <Label Content="InitContent"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center" />
                </Setter.Value>
            </Setter>

            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=TypeContent}" Value="{x:Null}">
                    <Setter Property="Content">
                        <Setter.Value>
                            <StackPanel Name="NullStackPanel">
                                <TextBox Name="Waldo" Text="DynamicText" />
                                <Button Width="100" Height="30" Content="DynamicButton" />
                            </StackPanel>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <Grid>
        <ContentControl Name="MainContentControl" />

        <Button Name="SetContentType"
                Width="100"
                Height="30" 
                HorizontalAlignment="Left"
                Content="SetContentType"
                Click="SetContentType_Click" />

        <Button Name="GetAccessToButton"
                Width="110"
                Height="30" 
                HorizontalAlignment="Right"
                Content="GetAccessToTextBox"
                Click="GetAccessToTextBox_Click" />
    </Grid>
</Window>

代码隐藏

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

    private void SetContentType_Click(object sender, RoutedEventArgs e)
    {
        TestData test = this.DataContext as TestData;

        test.TypeContent = null;
    }

    private void GetAccessToTextBox_Click(object sender, RoutedEventArgs e)
    {
        TextBox MyTextBox = null;
        StackPanel panel = MainContentControl.Content as StackPanel;

        foreach (object child in panel.Children)
        {
           if (child is TextBox)
           {
                MyTextBox = child as TextBox;
           }
        }

        if (MyTextBox != null) 
        {
            MyTextBox.Background = Brushes.Gainsboro;
            MyTextBox.Height = 100;
            MyTextBox.Text = "Got access to me!";
        }
    }
}

public class TestData : NotificationObject
{
    private string _typeContent = "Init";

    public string TypeContent
    {
        get
        {
            return _typeContent;
        }

        set
        {
            _typeContent = value;
            NotifyPropertyChanged("TypeContent");   
        }
    }
}

public class NotificationObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

关于c# - 如何在 WPF 中按名称查找样式触发器嵌入元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21977167/

相关文章:

c# - 图像源绑定(bind)到丢失的文件

c# - 绑定(bind)到以编程方式设置的 DataContext

c# - 如何在转发器中使用复选框列表?

c# - 无法在 CentOS 7 上运行 WinForms Mono 应用程序

c# - MVC 4 - Razor - 将变量传递到 href url

wpf - 如何向 WPF 上下文菜单添加条件?

wpf - 仅适用于 VS 设计 View 的 Blend 中的 UnresolvedAssemblyException - 在 VS 设计 View 中工作正常

c# - ASP CORE有任何图表库吗?

c# - WPF 中 MVVM 的项目结构

c# - 将贝塞尔曲线段或线的端点绑定(bind)到 WPF 中的其他形状?