DependencyObject.InvalidateProperty не работает
На основе документации через MSDN...
Вы также можете использовать InvalidateProperty для принудительная переоценка привязки против источника данных, который не способен для реализации рекомендованных Уведомление INotifyPropertyChanged механизм...
... код должен работать, но это не так.
public partial class Window1 : Window
{
private Payload _payload = new Payload();
public Window1()
{
InitializeComponent();
this.DataContext = _payload;
}
private void Invalidate(object sender, RoutedEventArgs e)
{
_payload.Timestamp = DateTime.Now.Add(TimeSpan.FromHours(1)).ToLongTimeString();
Button b = sender as Button;
b.InvalidateProperty(Button.ContentProperty);
}
}
public class Payload
{
private String _payload = DateTime.Now.ToLongTimeString();
public String Timestamp
{
get
{
return _payload;
}
set
{
_payload = value;
}
}
}
<Grid>
<Button Click="Invalidate"
Width="100"
Height="50"
Content="{Binding Path=Timestamp}"/>
</Grid>
Любая идея, что вызывает это поведение?
Ответы
Ответ 1
Как вы уже упоминали, это должно работать, но нет. Но есть простой способ:
// Doesn't work:
//b.InvalidateProperty(Button.ContentProperty);
// Works:
BindingOperations.GetBindingExpression(b, Button.ContentProperty).UpdateTarget();
Я отлаживался в исходном источнике, и все InvalidateProperty
в вашей ситуации заставляют кэшированное значение перечитываться из BindingExpression
в свойство Button
Content
. Оффлайн, я не знаю, когда это было бы необходимо, но не полезно, чтобы BindingExpression
перечитал исходное свойство.
Так как обходной путь является удобным и общим, единственное, что требуется, - это предоставить отчет об ошибке в Microsoft.
Ответ 2
Да. У меня есть мысль.
Причина, по которой ваш код не работает, заключается в том, что кнопка запрашивает новое значение, но объект привязки содержит старый, поскольку у него нет уведомления PropertyChanged. Цепочка изменений в стандартном сценарии выглядит так:
Payload.Timestamp → Объект привязки → Button.ContentProperty
В вашем сценарии, когда вы вызываете цепочку InvalidateProperty
:
Объект привязки → Button.ContentProperty
Итак, вы должны уведомить объект привязки, что его источник был изменен следующим кодом:
private void Invalidate(object sender, RoutedEventArgs e)
{
_payload.Timestamp = DateTime.Now.Add(TimeSpan.FromHours(1)).ToLongTimeString();
Button b = sender as Button;
BindingExpression be = b.GetBindingExpression(Button.ContentProperty);
be.UpdateTarget();
}
Как вы можете видеть, я даже не должен называть InvalidateProperty
, потому что механизм Binding из-за изменения основного источника автоматически заставляет Button обновлять содержимое.
Ответ 3
мы так и не работали, вот функция, которая делает трюк:
private void InvalidateProperty(DependencyProperty property,
FrameworkElement container)
{
container.SetBinding(property,
container.GetBindingExpression(property).ParentBinding);
}
И вот как мы это называем:
private void Invalidate(object sender, RoutedEventArgs e)
{
_payload.Timestamp = DateTime.Now.Add(TimeSpan.FromHours(1)).ToLongTimeString();
Button b = sender as Button;
//b.InvalidateProperty(Button.ContentProperty);
this.InvalidateProperty(Button.ContentProperty, b);
}
Мне также пришлось установить DataContext для _payload.