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, чтобы определить, что отображать.