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