在调查我正在处理的应用程序的问题时,我遇到了一个我不太了解的行为。看起来当你有一个TextBox(例如)带有绑定的Text属性时,系统会比你有一个静态文本时多接受一次布局传递。
请问任何人,解释为什么会发生这个额外的通行证?引擎是否先放置未绑定的控件然后将其绑定然后再次放置它?
为了测试这个,我构建了这样的测试用例:
我已经声明了一个继承自TextBox的类(所以我可以覆盖ArrangeOverride):
public class MultiBoundTextBox : TextBox
{
protected override Size ArrangeOverride(Size arrangeBounds)
{
Console.WriteLine("TextBox.Arrange");
return base.ArrangeOverride(arrangeBounds);
}
}
然后我在窗口中放置了这个文本框的实例:
<local:MultiBoundTextBox x:Name="tb">
Some text
</local:MultiBoundTextBox>
并为测试窗口添加了一些代码:
public Window11()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Console.WriteLine("Window.Loaded");
}
protected override Size ArrangeOverride(Size arrangeBounds)
{
Console.WriteLine("Window.Arrange");
return base.ArrangeOverride(arrangeBounds);
}
private void Window_Initialized(object sender, EventArgs e)
{
Console.WriteLine("Window.Initialized");
tb.DataContext = DateTime.Now;
}
现在当我运行这个时,我得到了这个输出:
Window.Initialized
Window.Arrange
TextBox.Arrange
Window.Arrange
Window.Loaded
但是如果我将Text属性更改为这样绑定:
<local:MultiBoundTextBox x:Name="tb">
<Binding Path="Day" Mode="OneWay" />
</local:MultiBoundTextBox>
我在输出中得到了这个:
Window.Initialized
Window.Arrange
TextBox.Arrange
Window.Arrange
TextBox.Arrange
Window.Arrange
Window.Loaded
注意另外一对TextBox.Arrange和Window.Arrange。为什么需要这个额外的通行证?
答案 0 :(得分:2)
引擎是否未绑定 首先控制然后绑定它 再次奠定它?
事实确实如此 - WPF data binding主要基于Dependency Properties构建,实际上影响了WPF布局流程,请参阅Layout Performance Considerations:
其值可以的依赖项属性 导致布局系统 初始化标有公开 标志。 AffectsMeasure和 AffectsArrange提供了有用的线索 属性值会改变的 强制布局进行递归更新 系统。一般来说,任何属性 可以影响元素的大小 边界框应该设置 AffectsMeasure标记为true。更多 有关信息,请参阅Dependency Properties Overview。
特别是关于您的问题,请参阅Optimizing Performance: Layout and Design中的引文:
如果发生以下任何操作,则再次调用布局传递过程:
- [...]
- 当依赖项属性的值发生更改时 标有影响该措施的元数据或安排通行证。
因此,我可以想象初始布局传递与以后绑定值更改的用例没有任何不同,这可以解释您遇到的行为。虽然此可能仍然错失了优化启动体验的机会,但通常的优化警告适用:没有测量时没有优化 - 例如这种假定的冗余(如果在技术上可以避免)可能没有可测量的影响,因为窗口/控件尚未显示等。
<强>调试:强>
要添加Drews suggestion of a debugging aid,有一个与.NET Framework 3.5中引入的绑定相关的新专用调试辅助工具,请参阅PresentationTraceSources.TraceLevel
- 示例:
<Window ... xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase">
<local:MultiBoundTextBox x:Name="tb">
<Binding Path="Day" Mode="OneWay"
diag:PresentationTraceSources.TraceLevel="High"/>
</local:MultiBoundTextBox>
</Window>
虽然有一些限制,但请务必阅读PresentationTraceSources Class
中的备注部分。
答案 1 :(得分:1)
不是直接答案,但是如果你将一个转换器添加到除了没有做任何事情的绑定之外怎么办,除了写出一条消息,告诉你在哪一点评估绑定?
public sealed class LoggingConverter : IValueConverter
{
public void Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
Console.WriteLine("Binding.Convert");
return value;
}
public void ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
Console.WriteLine("Binding.ConvertBack");
return value;
}
}