2009-04-09 1 views
8

Изучая проблему с приложением, над которым я работаю, я столкнулся с одним поведением, которое я не совсем понимаю. Кажется, что когда у вас есть TextBox (например) со связанным свойством Text, система принимает еще один макет, чем когда у вас есть статический текст.Отношение привязки и компоновки в WPF

Может ли кто-нибудь объяснить, почему этот дополнительный пропуск происходит? Вначале ли двигатель закладывает несвязанный элемент управления, а затем связывает его, а затем снова кладет его?

Чтобы проверить это, я построил такой тестовый случай:

Я объявил класс, унаследованный от 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 

Но если я изменить свойства текста, которые будут связаны следующим образом:

<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

+1 для детального случая воспроизведения. –

ответ

2

ли двигатель лежал несвязанного управления первым затем связывает его, а затем кладет ее еще раз?

Это действительно может быть так - WPF data binding построен в большой степени на Dependency Properties, которые делают на самом деле влияют на процесс компоновки WPF см Layout Performance Considerations:

зависимостей свойств, значения которых могут привести систему раскладки to be обозначены общественными знаками . AffectsMeasure и AffectsArrange предоставляют полезные подсказки как , на которые изменения стоимости имущества будут принудительное обновление по макете . В общем случае любое свойство, которое может повлиять на размер ограничивающей рамки элемента , должно соответствовать значению AffectsMeasure. Для получения дополнительной информации о , пожалуйста, см. Dependency Properties Overview.

И конкретно касается вашего вопроса см это цитата из Optimizing Performance: Layout and Design:

Процесс передачи макета вызывается снова, если любой из следующих действий происходит:

  • [...]
  • Когда происходит изменение значения свойства зависимостей, которое равно , отмеченного метаданными, влияющими на меру или организует проходы.

Следовательно, я мог себе представить, что первоначальный макет проход не был рассмотрен не отличается от случая использования связанного изменения значения позже, что бы объяснить поведение, которое вы испытываете. Хотя это может быть по-прежнему является упущенной возможностью для оптимизации опыта запуска, применяются обычные меры предосторожности: нет оптимизации без измерений - например. эта предполагаемая избыточность (если это технически можно избежать вообще) может не иметь ощутимое воздействие, потому что окно/управления еще не было показано, и т.д.


Debugging:

Чтобы добавить на Древса 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> 

Есть некоторые ограничения для этого работать Тхо ugh, обязательно прочитайте раздел Примечания в пределах PresentationTraceSources Class.

+0

Спасибо за указание 'PresentationTraceSources.TraceLevel' - похоже, что он будет полезен в один прекрасный день. –

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

+1 за предложение потенциальной помощи для отладки. –