【问题标题】:Auto-update of my view自动更新我的视图
【发布时间】:2009-06-22 08:05:04
【问题描述】:

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

  • 在 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(链接表)。

现在我在某处更改产品的属性,我希望视图会自动更新(因为我看到表实现了 INotifyPropertyChanged、INotifyPropertyChanging)。

但这不会发生。

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

【问题讨论】:

    标签: c# .net wpf xaml


    【解决方案1】:

    如果您只是将客户公开为IEnumerable&lt;Customer&gt;,它将不会更新。您需要将其公开为一个集合,该集合在其内容更改时触发事件。要么将其完全公开为您的客户表的任何类型(如果该类型引发 INotify 事件),或者您需要将其包装在类似 ObservableCollection&lt;&gt; 的东西中。

    【讨论】:

    • 如何查看(生成的)LINQ 代码:表(集合)没有实现 INotify,但表中的每个项目,“客户”都实现了 INotity。
    • @Robbert:与其将视图直接绑定到表格,不如遵循类似 MVVM 模式(参见此处:orbifold.net/default/?p=550)。在这种情况下,您将拥有一个模型类,它将包装对数据表的任何添加/删除。当你做事时,模型类会引发事件。您还将有一个视图模型类,该类将公开一个 ObservableCollection。您将能够在此 ObsColl 中添加/删除内容以响应模型中的事件。然后,您将视图绑定到视图模型。
    • 您不必将列表公开为 ObservableCollection,尽管这是最简单的做法。任何实现 INotifyCollectionChanged 的​​类型都可以。 ObservableCollection 实现了 INotifyCollectionChanged,因此使用它可能适合大多数情况。
    【解决方案2】:

    我正在使用 WPF + Linq to SQL 做一个 LOB 应用程序,而 Linq-To-Sql 集合未正确实现 INotifyCollectionChanged 的​​问题是我必须在系统的各个方面解决的问题。

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

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

    和/或

    1. 在您的实体类上实现 secondary 集合属性,这样您原来有 Customer.Products 的地方现在有 *Customer.Products_Observable",其中这个新的只读属性只返回一个 ObservableCollection,它包装了 Customer.Products 返回的任何内容。

    和/或

    1. 创建一个派生自 ObservableCollection 的新类,该类可识别 DataContext。如果您重写此类的 Add/Insert/Remove 方法,则对集合的任何更改都可以自动传播到 DataContext 和 InsertOnSubmit / DeleteOnSubmit 调用。

    以下是此类的一个示例:

    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) 一起使用(即从模型层/类中使用)。如果您想实现方法 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
    

    注意:实体只有在打开 ChangeTracking 的情况下附加到 DataContext 时才能找到它的 DataContext。上面的 hack(是的 - 这是一个 hack!)依赖于它。

    【讨论】:

      猜你喜欢
      • 2023-03-19
      • 2022-10-28
      • 1970-01-01
      • 2011-12-26
      • 2011-12-07
      • 2014-01-14
      • 1970-01-01
      • 2018-06-05
      • 1970-01-01
      相关资源
      最近更新 更多