Я заметил это, пытаясь установить привязку в течение короткого периода времени в коде. На самом деле, я просто хочу получить значение, предоставляемое привязкой. Поэтому я установил привязку, получаю значение свойства target и сразу очищаю привязку. Все хорошо, пока не будет установлен RelativeSource с режимом FindAncestor для привязки. В этом случае свойство target возвращает значение по умолчанию.Почему привязка к предку становится активным позже привязки к элементу по его имени или привязке к DataContext?
После некоторой отладки я обнаружил, что BindingExpression для привязки FindAncestor имеет свойство Свойство, установленное на Unattached. Для других типов привязок BindingExpression.Status имеет значение Active.
Я написал код, чтобы проиллюстрировать это.
Window1.xaml
<Window x:Class="Wpf_SetBindingInCode.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window"
Title="Window1"
Height="300" Width="300"
DataContext="DataContext content">
<StackPanel>
<Button Content="Set binding" Click="SetBindingButtonClick"/>
<TextBlock x:Name="TextBlock1"/>
<TextBlock x:Name="TextBlock2"/>
<TextBlock x:Name="TextBlock3"/>
</StackPanel>
</Window>
Window1.xaml.cs
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void SetBindingButtonClick(object sender, RoutedEventArgs e)
{
Binding bindingToRelativeSource = new Binding("DataContext")
{
RelativeSource = new RelativeSource { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(Window1) },
};
Binding bindingToElement = new Binding("DataContext")
{
ElementName = "Window"
};
Binding bindingToDataContext = new Binding();
BindingOperations.SetBinding(TextBlock1, TextBlock.TextProperty, bindingToRelativeSource);
BindingOperations.SetBinding(TextBlock2, TextBlock.TextProperty, bindingToElement);
BindingOperations.SetBinding(TextBlock3, TextBlock.TextProperty, bindingToDataContext);
Trace.WriteLine("TextBlock1.Text = \"" + TextBlock1.Text + "\"");
Trace.WriteLine("TextBlock2.Text = \"" + TextBlock2.Text + "\"");
Trace.WriteLine("TextBlock3.Text = \"" + TextBlock3.Text + "\"");
var bindingExpressionBase1 = BindingOperations.GetBindingExpressionBase(TextBlock1, TextBlock.TextProperty);
var bindingExpressionBase2 = BindingOperations.GetBindingExpressionBase(TextBlock2, TextBlock.TextProperty);
var bindingExpressionBase3 = BindingOperations.GetBindingExpressionBase(TextBlock3, TextBlock.TextProperty);
Trace.WriteLine("bindingExpressionBase1.Status = " + bindingExpressionBase1.Status);
Trace.WriteLine("bindingExpressionBase2.Status = " + bindingExpressionBase2.Status);
Trace.WriteLine("bindingExpressionBase3.Status = " + bindingExpressionBase3.Status);
}
}
Код выше производит следующий вывод:
TextBlock1.Text = ""
TextBlock2.Text = "DataContext content"
TextBlock3.Text = "DataContext content"
bindingExpressionBase1.Status = Unattached
bindingExpressionBase2.Status = Active
bindingExpressionBase3.Status = Active
Но, несмотря на это все три TextBlocks на форме ожидаемые значения - «Содержимое DataContext».
Так что мои вопросы:
Почему RelativeSourceMode.FindAncestor связывания не дает значение сразу после BindingOperations.SetBinding (...) называется?
Есть ли способ принудительно связать этот вид привязки для обновления цели ? Я попытался вызвать bindingExpression.UpdateTarget() - он не работает, как ожидалось.
Отличное объяснение, спасибо, спасибо! Но как насчет моего второго вопроса? Знаете ли вы способ принудительно привязать выражение привязки к контексту дерева? –
Вызовите метод 'UpdateLayout' для любого' UIElement' из текущего потока. –
Да, вызывается 'UpdateLayout' для данного примера. Хотя в моем реальном сценарии это не так ... Во всяком случае, я отметил ответ как принятый. Благодаря! –