【问题标题】:Binding and Layout relation in WPFWPF中的绑定和布局关系
【发布时间】:2010-10-18 14:00:55
【问题描述】:

在调查我正在处理的应用程序的问题时,我遇到了一种我不太了解的行为。似乎当您有一个带有绑定 Text 属性的 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。为什么需要这个额外的通行证?

【问题讨论】:

  • +1 详细复制案例。

标签: wpf layout binding


【解决方案1】:

引擎是否放空了 先控制然后绑定它然后 再来一次?

可能确实是这样—— WPF data binding 在很大程度上建立在 Dependency Properties 之上,这实际上会影响 WPF 布局过程,请参阅 Layout Performance Considerations

依赖属性的值可以 使布局系统成为 初始化被标记为公共 标志。 AffectsMeasureAffectsArrange 提供有用的线索 属性值将更改为 通过布局强制递归更新 系统。一般来说,任何财产 可以影响元素的大小 边界框应该设置 AffectsMeasure 标志为真。更多 信息请见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 中的备注部分。

【讨论】:

  • 感谢您指出PresentationTraceSources.TraceLevel -- 看起来有一天它会很有用。
【解决方案2】:

不是直接的答案,但是如果您将转换器添加到绑定中,除了写出一条消息,告诉您在哪个点评估绑定之外什么都不做?

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

【讨论】:

    猜你喜欢
    • 2011-12-13
    • 2013-06-29
    • 2011-12-27
    • 2011-05-11
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-24
    相关资源
    最近更新 更多