Как использовать PropertyChanged для передачи через DataTemplate? - PullRequest
0 голосов
/ 04 мая 2011

Вопрос прост: как я могу вызвать изменение объекта dataObject без точного изменения объекта dataObject и увидеть это изменение в визуальном элементе?

DataObject:

ProductData : INotifyPropertyChanged
{
    private ProductPartData myProductPartData;

    public ProductPartData ProductPartData
    {
        get
        {
            return myProductPartData;
        }
        set
        {
            if (value != myProductPartData)
            {
                myProductPartData = value;
                OnNotifyPropertyChanged("ProductPartData");
            }
        }
    }
}

DataTemplate:

 <DataTemplate
    DataType="{x:Type ProductData}"
    >
    <VisualProduct
        ProductPartData="{Binding Path=ProductPartData, Mode=OneWay}"
        />
</DataTemplate>

А теперь в виртуальной машине у меня есть:

product.OnNotifyPropertyChanged("ProductPartData");

Проблема: Даже еслиметод get для ProductPart вызывается, когда я выполняю OnNotifyPropertyChanged, визуал не уведомляется, поскольку это тот же экземпляр ProductPartData.

Как вызвать изменение, видимое визуалом, без изменения экземпляра?Спасибо,

Ответы [ 5 ]

3 голосов
/ 05 мая 2011

Daniel

Решением является использование метода UpdateTarget () класса BindingExpression, таким образом, цель привязки обновляется независимо от того, что; конечно, ваш конвертер также будет поражен - если таковой имеется. Так как я предполагаю, что у вас нет доступа к вашему визуалу в Продукте, вы можете использовать прикрепленное свойство и в его обратном вызове вы можете получить BindingExpression и вызвать UpdateTarget () для него.

Обратите внимание, что я использую простой TextBlock в качестве визуального объекта данных.

public class BindingHelper
{
    public static bool GetRefreshBinding(DependencyObject obj)
    {
        return (bool) obj.GetValue(RefreshBindingProperty);
    }

    public static void SetRefreshBinding(DependencyObject obj, bool value)
    {
        obj.SetValue(RefreshBindingProperty, value);
    }

    // Using a DependencyProperty as the backing store for RefreshBinding.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RefreshBindingProperty =
        DependencyProperty.RegisterAttached("RefreshBinding", typeof(bool), typeof(BindingHelper), new UIPropertyMetadata(false, OnRefreshBindingPropertyChanged));

    static void OnRefreshBindingPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs ea)
    {
        TextBlock elem = o as TextBlock;
        if (elem != null)
        {
            BindingExpression bEx = elem.GetBindingExpression(TextBlock.TextProperty);
            if (bEx != null)
            {
                bEx.UpdateTarget();
            }
        }
    }
}

Кроме того, в вашем объекте данных вы можете создать новое свойство bool (назовем его ShouldRefresh), которое привязано к присоединенному свойству в шаблоне - это вызовет изменение свойства точки доступа:

<DataTemplate DataType="{x:Type local:ProductData}">
        <TextBlock Text="{Binding Path=Name, Converter={StaticResource BlankConverter}}"
                   local:BindingHelper.RefreshBinding="{Binding Path=ShouldRefresh}"/>
    </DataTemplate>

Таким образом, таким образом, когда вы хотите обновить цель с помощью привязки, вы можете установить:

ShouldRefresh = !ShouldRefresh

в вашем классе данных.

НТН.

1 голос
/ 11 июля 2014

Мы столкнулись с такого рода проблемами с данными, поступающими из базы данных и преобразованными в DTO (объект передачи данных).

Наш базовый класс для DTO переопределяет метод объекта, такой как Equals() и GetHashCode() какfollow:

public override Boolean Equals(Object obj)
{
    // Null reference
    if (null == obj)
        return false;

    // Same reference
    if (Object.ReferenceEquals(this, obj))
        return true;

    EntityDTOBase<TEntity> entiteObj = obj as EntityDTOBase<TEntity>;
    if (null == entiteObj)
        return false;
    else
        return Equals(entiteObj);
}

public Boolean Equals(EntityDTOBase<TEntity> other)
{
    // Null reference
    if (null == other)
        return false;

    // Same reference
    if (Object.ReferenceEquals(this, other))
        return true;

    // No Id: cannot be compared, return false
    if (this.id == TypeHelper.DefaultValue<long>())
        return false;

    // Id comparison
    if (this.id != other.id)
        return false;

    return true;
}

public override Int32 GetHashCode()
{
    return this.id.GetHashCode();
}

Таким образом, проблема заключалась в том, что мы снова загружали одну и ту же сущность из базы данных, так как идентификатор такой же, некоторые привязки не были должным образом обновлены.

Эта конкретная проблема былаобойти, добавив дополнительный виртуальный метод EqualsExtended(), реализация которого по умолчанию просто возвращает true:

protected virtual Boolean EqualsExtended(EntityDTOBase<TEntity> other)
{
    return true;
}

public Boolean Equals(EntityDTOBase<TEntity> other)
{
  /// Same code as before (except last line):
  return EqualsExtended(other);
}

Теперь в любой реализации нашего класса DTO мы можем добавить некоторую логику, чтобы Equals() возвращал false в некоторыхситуации, например, путем добавления метки времени, когда данные извлекаются из базы данных:

protected override Boolean EqualsExtended(EntityDTOBase<Act> other
{
    if (this.Timestamp != other.Timestamp)
    {
        return false;
    }
    return true;
}

Короче говоря, один из способов обойти эту проблему - заставить ваш экземпляр класса выглядеть иначе, когда вы хотитеГрафический интерфейс для обновления соответственно.

1 голос
/ 04 мая 2011

Если вы вызовете событие PropertyChanged, и новое значение свойства будет равно значению, которое уже имеет WPF, оно просто проигнорирует вас.У вас есть пара опций:

«Быстрый» способ - установить для свойства значение null, а затем снова вернуться к правильному значению, гарантируя, что события PropertyChanged вызываются каждый раз.Это грязно, но работает каждый раз.

«Правильный» способ - принудительно обновить связывание, как обсуждалось в этой публикации Хайме Родригесом .Потому что ваше визуальное представление основано на данных, хотя получение "dependencyObject" для передачи в вызов в этом посте немного сложно.Вам может понадобиться использовать метод FindName шаблона, как описано в этом посте Джоша Смита .

0 голосов
/ 04 мая 2011

Помимо соглашений об именах (и при условии лишь опечаток при наборе текста) проблема, вероятно, находится внутри вашего класса ProductPartData.Он также реализует INotifyPropertyChanged?

0 голосов
/ 04 мая 2011

Возможно, проблема в том, что вы возвращаете GuiProductPartData набрал myProductPartData с ProductPartData набрал ProductPartData? Но в любом случае это не должно быть так:)

Также не рекомендуется использовать имя переменной, совпадающее с типом, поэтому у вас не должно быть свойства ProductPartData ProductPartData.

...