【问题标题】:How do I open a WPF window in AddNew mode before any data has been loaded?如何在加载任何数据之前以 AddNew 模式打开 WPF 窗口?
【发布时间】:2011-02-02 15:43:33
【问题描述】:

我想在 AddNew 模式下打开一个 WPF4/EF4 表单,以便用户可以在从数据库中选择任何数据之前开始在绑定控件中输入数据。我已经有一个“添加新记录”按钮,但它只适用于填充的 DataContext(我的 CollectionViewSource)。到目前为止的代码如下:

private void btnAddNewRecord_Click(object sender, RoutedEventArgs e)
{
    LabSample newEntity = _labEntitiesContext.LabSamples.CreateObject<LabSample>();
    _labEntitiesContext.LabSamples.AddObject(newEntity);
    _labSamplesListCollectionView.AddNewItem(newEntity);
}

背景:这是一个带有绑定控件的基本 WPF 应用程序。我从出现在我的数据源窗口中的实体框架模型开始。我从 DataSources 窗口中拖动了我的 LabSample 实体,让它在 XAML 的 Windows.Resources 部分中创建我的 CollectionViewSource (labSamplesViewSource)。我所有控件的 DataContext 都是 labSamplesViewSource。在实例化窗口时,我创建了一个名为 _labEntitiesContext 的新 LabEntities 对象。我使用 _labEntitiesContext 来构建过滤后的 ObjectQuery(of LabSample) 和 SaveChanges,但是对于这个 _labEntitiesContext 是如何连接到我的 CollectionViewSource 的,我有点困惑。如果您能在回答我的问题的同时澄清这一点,那将很有帮助。 注意:我还没准备好使用 MVVM。

当窗口加载时,我使用 this.FindResource 在名为 _labSamplesCollectionViewSource 的类级变量中获取对 CollectionViewSource 的引用。我允许用户输入搜索字段以用数据填充屏幕。我的 LoadData 例程如下所示:

System.Data.Objects.ObjectQuery<LabSample> labSamplesObjectQuery = this.GetLabSamplesFiltered_Query(_labEntitiesContext, sampleID_LIKE, xxx_LIKE, yyy_LIKE);
System.Data.Objects.ObjectResult<LabSample> labSamplesObjectResult = labSamplesObjectQuery.Execute(System.Data.Objects.MergeOption.AppendOnly);
_labSamplesCollectionViewSource.Source = new System.Collections.ObjectModel.ObservableCollection<LabSample>(labSamplesObjectResult);
_labSamplesListCollectionView = (ListCollectionView)_labSamplesCollectionViewSource.View;

上面设置的 _labSamplesListCollectionView 类级别变量在我的 btnAddNewRecord_Click 代码中使用。 在调用 LoadData 之前,_labSamplesListCollectionView 为 null,导致我的 AddNew 代码失败,并显示“对象引用未设置为对象的实例”。

我怎样才能做到这一点?我想知道我是否应该使用 _labSamplesListCollectionView.AddNew 而不是我目前的技术,但我也无法完成这项工作。非常感谢您的帮助。

【问题讨论】:

    标签: wpf entity-framework entity-framework-4 binding


    【解决方案1】:

    我正在编写一个执行类似操作的应用程序。然而,我正在使用 MVVM 模式,它允许我做一些整洁的事情。在我的工作中,我正在使用 Shipments。在 ShipmentsView 上,我可以单击“添加新”按钮,该按钮会触发绑定的命令属性,该属性位于关联的 ViewModel 类中。该命令方法如下所示:注意:此上下文中的视图不是 CollectionView,而是指 MVVM 视图类。

    Dim NewShipment = New Shipment()
    _Context.AddToShipments(NewShipment)
    Dim ShipVM = New ShipmentViewModel(NewShipment)
    ShipmentVMCollection.Add(ShipVM)
    Dim NewShipmentView as ShipmentView(ShipVM)
    

    我的 ShipmentView 处理它的放置和可见性,并且我的 Shipment 对象已经初始化了它的属性值,这样它就不会立即通过它的验证处理程序显示错误。这样,用户可以创建一个新的货件,如果他们被转移了,他们可以保存它并返回它,而无需一堆必填字段。

    当我使用 CollectionViewSource 时,我用我的实体的 ObservableCollection 填充它,然后在创建实体时将它们添加到该可观察集合中。 ObservableCollection 实现了 INotifyPropertyChanged 和 INotifyCollectionChanged 事件,并在发生某些事情时通知 UI,这一切都通过 CollectionViewSource 工作。

    您可以看看 MVVM 模式,它非常适合移动数据并将其保持在适当的范围内,并且有一些很好的 MVVM 框架可以帮助您使用 MVVM 制作一个漂亮的应用程序。

    如果你的应用程序很小,MVVM 可能有点过头了。但是,如果它超过了几个视图,它将变得笨拙且难以来回移动数据并使其保持最新和可维护。

    Wiki Article for MVVM - a pretty good place to start and get links

    这是我的一个 ViewModel 的构造函数。我意识到你现在不想在 MVVM 中实现,但后面的代码会是类似的。在这种情况下,我使用后台工作程序来获取我的实体记录,(构造函数调用是为此而立即可以忽略 View 设置),然后我链接我的 CVS,用我的 ObservableCollection 填充它,并将其设置为查看某个字段,以便我稍后对其进行过滤。

    Public Sub New(ByRef MyView As NTMsView)
        Me.New(ViewManagerService.CreateInstance, ViewModelUIService.CreateInstance)
        NTMsBackgroundWorker.RunWorkerAsync()
        _View = MyView
        _NTMCollectionViewSource = _View.FindResource("NTMCollectionViewSource")
        _NTMCollectionViewSource.Source = NTMs
        _NTMCollectionView = _NTMCollectionViewSource.View
    End Sub
    

    这是我的 AddRecord 方法的一个示例。然后我实例化一个新对象,将它添加到上下文中的适当集合中,保存它,执行存储过程,然后刷新上下文,因为存储过程对记录做了一些事情。然后我将对象添加到我的 Observable 中。

    Private Sub AddNTM()
        'Create an NTM Object.  
        Dim NewNTM As New NTMShipment()
        'Add it to the context
        _context.AddToNTMShipments(NewNTM)
        _context.SaveChanges()
        _context.MakeNewSecurityID(NewNTM.NTMShipID)
        _context.Refresh(RefreshMode.StoreWins, NewNTM)
        'Wrap it in a ViewModel and Add it to the NTMs collection
        NTMs.Add(New NTMViewModel(NewNTM))
    End Sub
    

    关于在创建 CollectionViewSource 之前创建新实体,有几个问题。您的编辑表单数据上下文是否与 CVS 相关?在我的表单中,CVS 仅与 ItemsControls 一起使用,因为它显示的是项目集合。如果您的编辑表单控件与 CVS 分离,则使用新实体填充它们应该不会有太大问题,当需要保存时,请检查 CVS 是否为空,如果是,则创建它然后填充它。

    如果这不是一个好的答案,您能否详细介绍一下您的应用程序的结构?

    【讨论】:

    • 我一直在研究MVVM,希望能尽快投入使用。对于学习 MVVM 的人,我发现 Karl Shifflett 的 In the Box 免费培训是一种独特的新学习方式 (karlshifflett.wordpress.com/2010/11/07/…)。你提供了一些很好的信息,但这不是我现在要找的。我希望有人可以向我展示几行代码,让我摆脱当前的“AddNew”障碍。
    • 至于您的上下文如何连接到 CollectionView,我不确定。我通常会自己处理(我将在我的帖子底部添加代码以举例说明)。在我的例子中,我创建了 CVS 并将它的源设置为 ObservableCollection 属性,然后我可以将对象添加到/从中删除。事实上,我真正使用 collectionViewSource 的唯一目的是记录并发(在 Master-Detail 中)和过滤/排序支持。
    【解决方案2】:

    当窗口加载或搜索没有返回记录时,我禁用所有数据输入控件,而不是在 AddNew 模式下打开窗口。单击“添加新记录”按钮时,我总是从仅包含一个新实体的新数据上下文重新开始。这意味着如果存在任何脏(修改)记录,我必须提示保存更改。该提示允许用户保存更改、放弃更改或继续编辑(从不进入 AddNew 模式)。这是 AddNew 代码:

    MessageBoxResult response = PromptToSaveChanges(ReasonForPromptToSave.LoadingData);
    
    if (response == MessageBoxResult.Cancel)  return;           
    
    LabSample newEntity = _labEntitiesContext.LabSamples.CreateObject<LabSample>();
    _labEntitiesContext.LabSamples.AddObject(newEntity);
    
    _labSamplesCollectionViewSource.Source = new ObservableCollection<LabSample>();
    _labSamplesListCollectionView = (ListCollectionView)_labSamplesCollectionViewSource.View;
    
    _labSamplesListCollectionView.AddNewItem(newEntity);
    _labSamplesListCollectionView.CommitNew();
    _labSamplesListCollectionView.Refresh();
    

    以下是将窗口置于 AddNew 模式的步骤:

    1) 提示保存更改。

    2) 创建一个新实体并将其添加到我的数据上下文中。

    3) 创建我的实体类型的新 ObservableCollection 并将其分配给我的 CollectionViewSource 的 .Source。请注意,_labSamplesCollectionViewSource 是对 XAML 的 CollectionViewSource 的引用,它是通过从数据源窗口中拖动表自动生成的。

    4) 将 CollectionViewSource 的 .View 分配给类级别的 ListCollectionView 变量。

    5) 将新实体添加到刚刚创建的 ListCollectionView。

    6) 在 ListCollectionView 上调用 CommitNew 和 Refresh

    我已经在这里回答了我自己的问题,但请记住,答案是反复试验的结果,可能并不理想。关于我对 _labEntitiesContext 如何连接到 CollectionViewSource 的困惑,我相信答案在 _labSamplesListCollectionView.AddNewItem(newEntity) 的行中,但我想看看所有对象如何相互引用的解释。

    我的最后评论/问题是,我对找到详细教授非 MVVM WPF/实体框架数据绑定的标准参考应用程序或文档的难度感到失望。 Microsoft 提倡拖放绑定,但没有给我们提供有关如何构建完整应用程序的参考。我很快就会转向 MVVM,同时,如果有人能指导我使用 WPF、非 MVVM 和实体框架的优秀资源或功能完整的应用程序,我将不胜感激。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      相关资源
      最近更新 更多