Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在WPF中按名称找到样式触发器嵌入元素?_C#_Wpf_Xaml_Triggers_Contentcontrol - Fatal编程技术网

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

C# 如何在WPF中按名称找到样式触发器嵌入元素?,c#,wpf,xaml,triggers,contentcontrol,C#,Wpf,Xaml,Triggers,Contentcontrol,首先,问题的核心是:如果通过样式触发器将元素指定为ContentControl的内容,我似乎无法通过名称找到它 现在,更详细地说:我有一个面板,它的布局和功能根据其数据上下文有很大的不同,这是一个来自bug仓库的bug。当该bug为null时,它是一个搜索表单,当它为非null时,它是该bug属性的简单查看器。然后,XAML看起来像: <ContentControl DataContext="..."> <ContentControl.Style>

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

现在,更详细地说:我有一个面板,它的布局和功能根据其数据上下文有很大的不同,这是一个来自bug仓库的bug。当该bug为null时,它是一个搜索表单,当它为非null时,它是该bug属性的简单查看器。然后,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>
我已经看到了很多关于这个主题的讨论,因为它涉及到触发器,而不是直接用触发器设置内容。可能是因为我这样做违反了各种最佳实践:)

谢谢大家!

如果通过样式触发器将元素指定为
ContentControl
Content
,我似乎无法按名称找到它

如果您需要在触发之前访问
内容
,则很可能不可能。在这种情况下,在DataTrigger发生后获取访问权限的主要任务是

我这样做违反了各种最佳实践

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

我创建了一个小示例来演示给定情况下的访问控制。有一个属性对应于内容的类型,默认值为
Init
。如果为此属性指定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!";
    }
}
下面是一个完整的示例:

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

感谢您周到详细的解释!这种方法的特点是,它将用户界面结构的知识强制输入到代码隐藏中(即我们正在搜索的文本框是命名StackPanel的子项),但总体而言,它似乎是最不痛苦的方法。正如你所说的,对于一个小应用程序来说,最好不要过于沉迷于V/VM分离:)有点匆忙,我只是忘记了,离开了计算机一段时间。尽管有对抗性的反应,我还是照办了,并给予了应有的赞扬:)这是一个很好的回答,再次感谢。
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));
        }
    }
}