自动更新我的视图

时间:2009-06-22 08:05:05

标签: c# .net wpf xaml

我创建了一个具有以下内容的应用程序:

  • 在VS2008中创建的数据库,LINQ to SQL
  • 数据库视图:

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)。

但这不会发生。

我可以全部触发它,但在我开始这样做之前,我想知道是否应该自动发生。任何人吗?

2 个答案:

答案 0 :(得分:2)

如果您只是将客户公开为IEnumerable<Customer>,它就不会更新。您需要将其公开为一个集合,以便在内容发生更改时触发事件。要么将它完全暴露为您的Customers表的任何类型(如果该类型引发INotify事件),或者您需要将其包装为类似ObservableCollection<>的内容。

答案 1 :(得分:0)

我正在使用WPF + Linq to SQL做一个LOB应用程序,并且Linq-To-Sql集合没有正确实现INotifyCollectionChanged的问题是我必须在系统的每个方面解决的问题。 / p>

到目前为止,我发现的最佳解决方案是执行以下任一操作:

  1. 在DataContext类上创建模型层,以便您的GUI代码仅与模型层交互,而不是直接与DataContext交互。在业务逻辑方法中,始终将返回的集合包装在ObservableCollection
  2. 和/或

    1. 在您的实体类上实现辅助集合属性,例如您最初拥有 Customer.Products 的位置,您现在拥有* Customer.Products_Observable“,其中这个新的只读属性只返回一个ObservableCollection,它包装了Customer.Products返回的任何内容。
    2. 和/或

      1. 创建一个从ObservableCollection派生的新类,它可以识别DataContext。如果覆盖此类的Add / Insert / Remove方法,则对集合的任何更改都可以自动传播到DataContext和InsertOnSubmit / DeleteOnSubmit调用。
      2. 以下是此类的一个示例:

        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。上面的黑客(是的 - 这是一个黑客!)依赖它。