2011-07-15 29 views
2

我在我的應用程序中使用了EntityFramework,WPF和MVVM,並且在更新EntityObjects之間的關係數據綁定時遇到了一些問題。我能夠將我的問題縮小到只有幾行XAML,我希望有人能夠幫助我,因爲我對EF和MVVM還不是很有信心。EF EntityObject不更新關係的數據綁定

無論如何,在這裏我們去與簡化的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個標籤來測試我的數據綁定。使用DatePicker更改File.SentDate會將數據綁定更新爲最後一個Label,而不會出現問題。

現在文件屬於EntityObject類型,並且有一個類型爲GUID的SenderId屬性。它也通過發件人屬性與我的聯繫人有關係。但是,SenderId是通過發件人關係與文件相關的相應聯繫人實體對象的GUID。一個文件只能有一個Contact類型的發件人。

不管怎樣,當我使用組合框選擇另一個發件人時,顯示File.SenderId屬性的Label會得到正確更新。但是,具有File.Sender.Name屬性的文件,即使用reléationship的文件不會被更新。

所以我猜測,關於更新EF中關係的數據綁定有一些特殊之處。

有人可以請建議一個解決方案嗎?

回答

1

不幸的是,實體框架不會通知關聯屬性何時更改。這就是爲什麼你的綁定不起作用。

問題報告給微軟:http://connect.microsoft.com/VisualStudio/feedback/details/532257/entity-framework-navigation-properties-don-t-raise-the-propertychanged-event

另一種解決方法是通過的WPF Application Framework (WAF)BookLibrary示例應用程序中。 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"); 
} 
+0

謝謝。很高興知道這與我的愚蠢無關。雖然早些時候知道這會節省我幾個小時抓我的頭:-) –

0

看起來我找到了解決方案,但對我來說它更像是一種解決方法。這不是我想到的解決方案,而是它的工作原理。

除了一件事情之外,XAML仍然與上面相同。代替結合File.Sender.Name,我結合File.SenderName這樣的:

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

發送者姓名在這種情況下是在我的局部類添加這樣的目標文件的一個屬性:

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屬性。而已。奇蹟般有效。雖然我仍然不相信這是它應該工作的方式。

+0

我認爲將BindableSender等屬性添加到部分類中會更有意義。它只會獲取/設置發件人屬性並觸發PropertyChanged事件。然後你可以綁定到那個,就像'{Binding Path = File.BindableSender.Name}' – Mtihc

0

另一個解決方法,如果你只是想要一個名字,就是爲發件人覆蓋ToString()並直接綁定到發件人。這種解決方法很好,因爲大多數情況下,當我們將數據綁定到屬性的屬性時,我們會執行此操作,以便將對象集的「名稱」設置爲屬性值。如果您編輯tt文件以向所有類定義添加部分內容,此方法也適用於數據庫優先方法。

所以你添加一個文件包含你的entites的的ToString擴展,並在其中添加類似這樣:

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

這樣你就可以進行數據綁定

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

現在的數據綁定將檢測的發件人發生變化,當它發生變化時,它會調用ToString來確定要顯示的內容。

另一方面,如果您需要綁定到另一個非標準屬性,您可能會遇到問題。我記得使用DataContext和模板解決它的成功。您綁定到發件人並使用DataTemplate來確定要顯示的內容。