代码之家  ›  专栏  ›  技术社区  ›  Alan Mendelevich

WPF中的绑定和布局关系

  •  8
  • Alan Mendelevich  · 技术社区  · 16 年前

    在调查我正在开发的应用程序的问题时,我遇到了一个我不太理解的行为。看起来,当您有一个具有绑定文本属性的文本框(例如)时,系统会比您有一个静态文本时多进行一次布局传递。

    有人能解释一下为什么会有额外的通行证吗?引擎是否先放置未绑定的控件,然后将其绑定,然后再次放置?

    为了测试这个,我构建了这样的测试用例:

    我声明了从文本框继承的类(这样我可以重写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
    

    但如果我将文本属性更改为这样绑定:

        <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
    

    注意额外的一对文本框。排列和window.arrange。为什么需要额外的通行证?

    2 回复  |  直到 16 年前
        1
  •  2
  •   Community CDub    7 年前

    发动机是否松开 首先控制,然后绑定它,然后 再放一遍?

    可能确实是这样- WPF data binding 是建立在 Dependency Properties ,这实际上会影响WPF布局过程,请参见 Layout Performance Considerations :

    其值可以 使布局系统 初始化时用public标记 旗帜。 AffectsMeasure AffectsArrange 提供有用的线索 属性值更改将 强制布局进行递归更新 系统。一般来说,任何财产 会影响元素的大小 边界框应设置 影响测量 标志为真。为了更多 信息,请参见 Dependency Properties Overview .

    特别是关于你的问题,请看以下引文: Optimizing Performance: Layout and Design :

    如果发生以下任何操作,将再次调用布局传递过程:

    • […]
    • 当依赖项属性的值发生更改时, 标记有影响度量值或排列过程的元数据。

    因此,我可以想象,最初的布局过程与稍后的绑定值更改用例没有任何不同,这将解释您正在经历的行为。虽然这 可以 仍然是优化启动体验的错失机会,通常的优化注意事项适用: 没有度量就没有优化 -例如,这种假定的冗余(如果技术上完全可以避免)可能没有可测量的影响,因为窗口/控件尚未显示等。


    调试:

    添加DRIWS 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 .

        2
  •  1
  •   Drew Noakes    15 年前

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

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