DependencyObject.InvalidateProperty не работает - PullRequest
13 голосов
/ 08 февраля 2011

На основе документации через 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>

Есть идеи, что вызывает такое поведение?

Ответы [ 3 ]

14 голосов
/ 23 февраля 2011

Как вы упомянули, это должно работать, но не работает. Но есть простой обходной путь:

// Doesn't work:
//b.InvalidateProperty(Button.ContentProperty);

// Works:
BindingOperations.GetBindingExpression(b, Button.ContentProperty).UpdateTarget();

Я отладил в эталонном источнике, и все, что InvalidateProperty делает в вашей ситуации, заставляет кэшированное значение перечитываться из BindingExpression в свойство Button Content. Случайно, я не знаю, когда это было бы даже необходимо, но бесполезно заставлять BindingExpression перечитывать необработанное свойство.

Поскольку обходной путь удобен и носит общий характер, единственное дальнейшее действие, которое требуется, - это сообщение об ошибке в Microsoft.

3 голосов
/ 08 февраля 2011

Да.У меня есть идея.

Причина, по которой ваш код не работает, заключается в том, что кнопка запрашивает новое значение, но объект Binding содержит старое значение, поскольку у него нет уведомления PropertyChanged.Цепочка изменений в стандартном сценарии выглядит следующим образом:

Payload.Timestamp -> объект привязки -> Button.ContentProperty

В вашем сценарии при вызове InvalidateProperty chainis:

Объект привязки -> 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, потому что механизм связывания из-за изменения базового источника автоматически заставит Button обновить содержимое.

1 голос
/ 22 февраля 2011

мы никогда не работали, вот функция, которая делает свое дело:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...