我创建了一个具有以下内容的应用程序:
XAML部分
<CollectionViewSource x:Key="CustomerView" Source="{Binding Source={x:Static Application.Current}, Path=Customers}" />
C#部分
public IEnumerable<Customer> Customers
{
get
{
var database = new ApplicationDataContext();
return from customer in database.Customers
select customer ;
}
}
该视图不仅显示客户,还显示Customers.Products(链接表)等子表。
现在我在某处更改了Product的属性,我希望View能够自动更新(因为我看到这些表实现了INotifyPropertyChanged,INotifyPropertyChanging)。
但这不会发生。
我可以全部触发它,但在我开始这样做之前,我想知道是否应该自动发生。任何人吗?
答案 0 :(得分:2)
如果您只是将客户公开为IEnumerable<Customer>
,它就不会更新。您需要将其公开为一个集合,以便在内容发生更改时触发事件。要么将它完全暴露为您的Customers表的任何类型(如果该类型引发INotify事件),或者您需要将其包装为类似ObservableCollection<>
的内容。
答案 1 :(得分:0)
我正在使用WPF + Linq to SQL做一个LOB应用程序,并且Linq-To-Sql集合没有正确实现INotifyCollectionChanged的问题是我必须在系统的每个方面解决的问题。 / p>
到目前为止,我发现的最佳解决方案是执行以下任一操作:
和/或
和/或
以下是此类的一个示例:
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Linq
Imports System.Data.Linq
Public Class ObservableEntityCollection(Of T As {Class})
Inherits ObservableCollection(Of T)
Private _Table As Table(Of T)
Public Sub New(ByVal Context As DataContext)
Me._Table = Context.GetTable(Of T)()
End Sub
Public Sub New(ByVal Context As DataContext, ByVal items As IEnumerable(Of T))
MyBase.New(items)
Me._Table = Context.GetTable(Of T)()
End Sub
Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As T)
_Table.InsertOnSubmit(item)
MyBase.InsertItem(index, item)
End Sub
Public Shadows Sub Add(ByVal item As T)
_Table.InsertOnSubmit(item)
MyBase.Add(item)
End Sub
Public Shadows Sub Remove(ByVal item As T)
If MyBase.Remove(item) Then
_Table.DeleteOnSubmit(item)
End If
Dim deletable As IDeletableEntity = TryCast(item, IDeletableEntity)
If deletable IsNot Nothing Then deletable.OnDelete()
End Sub
Protected Overrides Sub RemoveItem(ByVal index As Integer)
Dim Item As T = Me(index)
_Table.DeleteOnSubmit(Item)
MyBase.RemoveItem(index)
End Sub
End Class
Public Interface IDeletableEntity
Sub OnDelete()
End Interface
IDeletable接口允许您在实体类上实现特定逻辑(例如清理外键和删除子对象)。
请注意,该类需要DataContext引用作为构造函数,这使得它非常适合与上面的场景1)一起使用(即从Model层/类中使用)。如果你想实现方法2)[即在实体上作为属性],那么你可以给附加实体提供“查找”它们的DataContext的能力,如下所示:
[在实体类:]
Public Property Context() As DataContext
Get
If _context Is Nothing Then
_context = DataContextHelper.FindContextFor(Me)
Debug.Assert(_context IsNot Nothing, "This object has been disconnected from it's DataContext, and cannot perform the requeted operation.")
End If
Return _context
End Get
Set(ByVal value As DataContext)
_context = value
End Set
End Property
Private _context As DataContext
[作为实用工具类]:
Public NotInheritable Class DataContextHelper
Private Const StandardChangeTrackerName As String = "System.Data.Linq.ChangeTracker+StandardChangeTracker"
Public Shared Function FindContextFor(ByVal this as DataContext, ByVal caller As Object) As JFDataContext
Dim hasContext As Boolean = False
Dim myType As Type = caller.GetType()
Dim propertyChangingField As FieldInfo = myType.GetField("PropertyChangingEvent", BindingFlags.NonPublic Or BindingFlags.Instance)
Dim propertyChangingDelegate As PropertyChangingEventHandler = propertyChangingField.GetValue(caller)
Dim delegateType As Type = Nothing
For Each thisDelegate In propertyChangingDelegate.GetInvocationList()
delegateType = thisDelegate.Target.GetType()
If delegateType.FullName.Equals(StandardChangeTrackerName) Then
propertyChangingDelegate = thisDelegate
Dim targetField = propertyChangingDelegate.Target
Dim servicesField As FieldInfo = targetField.GetType().GetField("services", BindingFlags.NonPublic Or BindingFlags.Instance)
If servicesField IsNot Nothing Then
Dim servicesObject = servicesField.GetValue(targetField)
Dim contextField As FieldInfo = servicesObject.GetType.GetField("context", BindingFlags.NonPublic Or BindingFlags.Instance)
Return contextField.GetValue(servicesObject)
End If
End If
Next
Return Nothing
End Function
注意:如果实体附加到DataContext并且启用了ChangeTracking,则实体只能找到它的DataContext。上面的黑客(是的 - 这是一个黑客!)依赖它。