首先,问题的核心:如果通过样式触发器将元素指定为 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 aContentControl
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/