EF EntityObject не обновляет привязки данных отношений

Я использую EntityFramework, WPF и MVVM в своем приложении и у меня возникли некоторые проблемы с обновлением привязки данных отношений между EntityObjects. Я смог уменьшить свою проблему до нескольких строк XAML, и я надеюсь, что кто-то может мне помочь, так как я все еще не очень уверен в EF и MVVM.

В любом случае, здесь мы используем упрощенный XAML:

    <DatePicker Grid.Row="2" Grid.Column="1" 
                    SelectedDate="{Binding Path=File.SentDate, 
StringFormat={}{0:dd/MM/yyyy}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    VerticalAlignment="Center" IsEnabled="{Binding Path=IsEnabled}"/>

        <ComboBox Grid.Row="3" Grid.Column="1" ItemsSource="{Binding Contacts}" DisplayMemberPath="Name" 
                  SelectedItem="{Binding Path=File.Sender, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEditable="True"
                  VerticalAlignment="Center">
        </ComboBox>

        <Label Content="{Binding Path=File.SenderId}" Grid.Row="4"/>
        <Label Content="{Binding Path=File.Sender.Name}" Grid.Row="5"/>
        <Label Content="{Binding Path=File.SentDate}" Grid.Row="6"/>

Я использую последние 3 ярлыка для проверки привязки данных. Изменение File.SentDate с использованием DatePicker обновляет привязку данных до последней метки без проблем.

Теперь File имеет тип EntityObject и имеет свойство SenderId типа GUID. Он также имеет отношение к моим контактам через свойство Sender. Обязательно, SenderId - это GUID соответствующего Contact EntityObject, который связан с File через отношение Sender. Файл может иметь только одного отправителя типа "Контакт".

В любом случае происходит следующее: когда я выбираю другого отправителя с помощью комбинированного списка, метка, отображающая свойство File.SenderId, корректно обновляется. Однако тот, у которого есть свойство File.Sender.Name, то есть тот, который использует связь, не обновляется.

Поэтому я предполагаю, что в обновлении привязки данных в EF есть что-то особенное.

Может кто-нибудь предложить решение этой проблемы?

3 ответа

Решение

К сожалению, Entity Framework не уведомляет об изменении свойства ассоциации. Вот причина того, почему твоя привязка не сработала.

О проблеме сообщается в Microsoft: http://connect.microsoft.com/VisualStudio/feedback/details/532257/entity-framework-navigation-properties-don-t-raise-the-propertychanged-event

Другой обходной путь показан в примере приложения BookLibrary WPF Application Framework (WAF). Класс Book прослушивает событие AssociationChanged и вызывает соответствующее событие PropertyChanged.

public Book()
{
    …
    LendToReference.AssociationChanged += LendToReferenceAssociationChanged;
}

private void LendToReferenceAssociationChanged(object sender, 
        CollectionChangeEventArgs e)
{
    // The navigation property LendTo doesn't support the PropertyChanged event. 
    // We have to raise it ourselves.
    OnPropertyChanged("LendTo");
}

Похоже, я нашел решение, хотя для меня это больше похоже на обходной путь. Это не то решение, которого я ожидал, но оно работает.

XAML все тот же, что и выше, за исключением одной вещи. Вместо привязки к File.Sender.Name, я привязываюсь к File.SenderName следующим образом:

<Label Content="{Binding Path=File.SenderName}" Grid.Row="4"/>

SenderName в этом случае является свойством объекта File, который я добавил в частичный класс, например так:

public partial class File
{
        public string SenderName
        {
            get
            {
                if (this.Sender != null)
                {
                    return this.Sender.Name;
                }

                return string.Empty;
            }
        }
protected override void OnPropertyChanged(string property)
        {

            if (property == "SenderId")
            {
                OnPropertyChanged("SenderName");
            }
            base.OnPropertyChanged(property);
        }
}

Итак, что здесь происходит, так это то, что если свойство SenderId изменяется, я говорю платформе также обновить свойство SenderName. Вот и все. Работает как шарм. Хотя я до сих пор не убежден, что так оно и должно работать.

Другой обходной путь, если вам просто нужно имя, - переопределить ToString() для Отправителя и связать его непосредственно с отправителем. Этот обходной путь хорош, потому что большую часть времени, когда мы привязываем данные к свойству свойства, мы делаем это, чтобы получить "имя" объекта, установленное в качестве значения свойства. Также этот метод работает и для подхода "Сначала база данных", если вы редактируете файлы tt, чтобы добавить частичное во все определения классов.

Таким образом, вы добавляете файл, содержащий расширения ToString ваших Entites, и в него вы добавляете что-то вроде этого:

public partial Contacts 
{
    public override string ToString()
    {
        return Name;
    }
}

так что вы можете найти данные

<Label Content="{Binding Path=File.Sender}" Grid.Row="5"/>

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

С другой стороны, если вам нужно привязать к другому нестандартному свойству, у вас могут возникнуть проблемы. Я помню, как успешно использовал DataContext и шаблоны, чтобы обойти это. Вы связываетесь с Sender и используете DataTemplate, чтобы определить, что отображать.

Другие вопросы по тегам