C# WPF:初始可见性和模板加载
我遇到了一个问题,即如果某个用户控件在初始化时不可见,则该控件上的绑定未正确设置。我使用以下简化的控件复制了该问题:C# WPF:初始可见性和模板加载,c#,wpf,xaml,C#,Wpf,Xaml,我遇到了一个问题,即如果某个用户控件在初始化时不可见,则该控件上的绑定未正确设置。我使用以下简化的控件复制了该问题: public class Test3 : Control { static Test3() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Test3), new FrameworkPropertyMetadata(typeof(Test3)));
public class Test3 : Control
{
static Test3()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Test3), new FrameworkPropertyMetadata(typeof(Test3)));
}
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string),
typeof(Test3), new UIPropertyMetadata("test3 default text"));
}
public class Test2 : Control
{
static Test2()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Test2), new FrameworkPropertyMetadata(typeof(Test2)));
}
public FrameworkElement Test3Control
{
get { return (FrameworkElement)GetValue(Test3ControlProperty); }
set { SetValue(Test3ControlProperty, value); }
}
public static readonly DependencyProperty Test3ControlProperty =
DependencyProperty.Register("Test3Control", typeof(FrameworkElement),
typeof(Test2), new UIPropertyMetadata(null));
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string), typeof(Test2),
new UIPropertyMetadata("test2 default text"));
}
public partial class Test1 : UserControl
{
public Test1()
{
InitializeComponent();
}
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(string),
typeof(Test1), new UIPropertyMetadata("test1 default text"));
}
usercontrol的XAML:
<UserControl x:Class="Test.Test1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dummy="clr-namespace:WpfTestApplication.Test"
Name="ucThis">
<UserControl.Resources>
<Style TargetType="{x:Type test:Test2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type test:Test2}">
<GroupBox Header="Test2">
<StackPanel>
<TextBox IsEnabled="False" Text="{TemplateBinding Test}"/>
<GroupBox Header="Test3">
<ContentPresenter Content="{TemplateBinding Test3Control}"/>
</GroupBox>
</StackPanel>
</GroupBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<test:Test2 Test="{Binding ElementName=ucThis,Path=Test}">
<test:Test2.Test3Control>
<test:Test3 Test="{Binding ElementName=ucThis,Path=Test}">
<test:Test3.Template>
<ControlTemplate TargetType="{x:Type test:Test3}">
<TextBox IsEnabled="False" Text="{TemplateBinding Test}"/>
</ControlTemplate>
</test:Test3.Template>
</test:Test3>
</test:Test2.Test3Control>
</test:Test2>
</Grid>
</UserControl>
。。。主窗口的XAML(无论如何,它的核心):
我希望在文本框(“tbInput”)中输入的任何文本都会显示在Test2和Test3框中——事实上,对于Test2的两个实例来说都是如此,但对于最初可见的Test3来说才是如此。最初折叠的Test3始终显示默认文本,即使在输入文本时它是可见的
我曾尝试使用Snoop对此进行调查,但当我使用Snoop对树的相关部分进行评估时,问题得到了纠正,因此没有多大帮助
是什么导致了这种行为?我怎样才能纠正它?我在哪里可以读到更多关于它的信息
更新:
通过查看输出窗口,我发现了以下错误消息:
System.Windows.Data错误:4:找不到引用为“ElementName=ucThis”的绑定源。BindingExpression:Path=Test;DataItem=null;目标元素为“Dummy3”(名称=“”);目标属性为“Test”(类型为“String”)
通过处理这些控件上已加载和初始化的事件,我可以看到在启动时加载Dummy1和Dummy2之后会发生此错误。Dummy 3在显示之前不会加载。我不确定您的具体问题,但我会将Test2的隐式样式定义移动到Generic.xaml模块,该模块必须位于“Themes”文件夹中。框架将自动扫描该文件以查找隐式样式。我不确定您的具体问题,但我会将Test2的隐式样式定义移动到Generic.xaml模块,该模块必须位于“Themes”文件夹中。框架将自动扫描该文件以查找隐式样式。我认为问题在于,由于模板尚未应用于折叠的
Test3
实例,因此它尚未插入到可视化树中。因此,创建绑定时,它不在外部Test1
实例的名称范围内,因此无法解析为ElementName
指定的名称ucThis
您可以通过将Test3Control
添加到Test2
的逻辑树中来处理此问题。尝试按如下方式修改依赖项属性定义:
public static readonly DependencyProperty Test3ControlProperty =
DependencyProperty.Register("Test3Control", typeof(FrameworkElement),
typeof(Test2),
new UIPropertyMetadata(null, OnTest3ControlPropertyChanged));
private static void OnTest3ControlPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var source = (Test2)d;
var oldValue = e.OldValue as FrameworkElement;
var newValue = e.NewValue as FrameworkElement;
if (oldValue != null)
source.RemoveLogicalChild(oldValue);
if (newValue != null)
source.AddLogicalChild(newValue);
}
在大多数情况下,当您向控件添加新的基于UIElement
的属性时,您需要确保将其添加到逻辑树中。这不是自动发生的。因此,它也不会自动添加到可视化树中。在这种情况下,它只加载到可视化树中,因为它显式插入到模板中
查看WPF核心控件的内部,如装饰器
(Border从中派生)及其子属性,以了解定义新控件类型时可能需要何种管道
还要注意有多少“子控件”属性是而不是依赖项属性。基于视觉的
依赖属性很容易出现问题,特别是当您试图通过setter或动画对其进行更改时。我发现最好通过简单地将子控件公开为常规CLR属性来阻止开发人员滥用属性并为自己制造麻烦。我认为问题在于,由于模板没有应用于折叠的Test3
实例,因此它没有插入到可视化树中。因此,创建绑定时,它不在外部Test1
实例的名称范围内,因此无法解析为ElementName
指定的名称ucThis
您可以通过将Test3Control
添加到Test2
的逻辑树中来处理此问题。尝试按如下方式修改依赖项属性定义:
public static readonly DependencyProperty Test3ControlProperty =
DependencyProperty.Register("Test3Control", typeof(FrameworkElement),
typeof(Test2),
new UIPropertyMetadata(null, OnTest3ControlPropertyChanged));
private static void OnTest3ControlPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var source = (Test2)d;
var oldValue = e.OldValue as FrameworkElement;
var newValue = e.NewValue as FrameworkElement;
if (oldValue != null)
source.RemoveLogicalChild(oldValue);
if (newValue != null)
source.AddLogicalChild(newValue);
}
在大多数情况下,当您向控件添加新的基于UIElement
的属性时,您需要确保将其添加到逻辑树中。这不是自动发生的。因此,它也不会自动添加到可视化树中。在这种情况下,它只加载到可视化树中,因为它显式插入到模板中
查看WPF核心控件的内部,如装饰器
(Border
从中派生)及其子属性,以了解定义新控件类型时可能需要何种管道
还要注意有多少“子控件”属性是而不是依赖项属性。基于视觉的
依赖属性很容易出现问题,特别是当您试图通过setter或动画对其进行更改时。我发现最好是通过简单地将子控件公开为常规CLR属性来阻止开发人员滥用属性并为自己制造麻烦。这是一种风格选择吗?该框架还将扫描页面中的隐式样式,很明显该样式是bei