如何在加载任何数据之前在AddNew模式下打开WPF窗口?

时间:2011-02-02 15:43:33

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

我想在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窗口中的Entity Framework模型开始。我从DataSources窗口拖动我的LabSample实体,让它在XAML的Windows.Resources部分创建我的CollectionViewSource(labSamplesViewSource)。我所有控件的DataContext都是labSamplesViewSource。当窗口被实例化时,我创建了一个名为_labEntitiesContext的新LabEntities对象。我使用_labEntitiesContext来构建我过滤的ObjectQuery(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而不是我当前的技术,但我也无法做到这一点。非常感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

我正在编写一个类似的应用程序。然而,我正在使用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)

My ShipmentView处理它的位置和可见性,我的Shipment对象初始化了它的属性值,因此它不会通过它的验证处理程序立即显示错误。通过这种方式,用户可以创建新的货件,如果他们得到了侧面跟踪,他们可以保存它并返回到它而不需要一堆必填字段。

当我使用CollectionViewSource时,我用我的实体的ObservableCollection填充它,然后在创建它时将实体添加到该observable集合。 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方法的一个例子。然后我实例化一个新对象,将其添加到Context中的相应集合,保存它,执行存储过程,然后刷新上下文,因为存储过程对记录做了一些事情。然后我将对象添加到我的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相关的datacontext?在我的表单中,CVS仅与ItemsControls一起使用,因为它显示了一组项目。如果您的编辑表单控件与CVS分离,那么使用新实体填充它们应该不会有太多麻烦,当需要保存时,检查CVS是否为空,如果是,则创建它然后填充它。

如果这不是一个好的答案,你能否扩展你的应用程序的结构?

答案 1 :(得分:0)

不是在AddNew模式下打开Window,而是在窗口加载时或搜索没有返回记录时禁用所有数据输入控件。单击“添加新记录”按钮后,我总是重新开始使用只包含一个新实体的新数据上下文。这意味着如果存在任何脏(修改)记录,我必须提示保存更改。该提示允许用户保存更改,放弃更改或继续编辑(从不进入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 / Entity Framework数据绑定的标准参考应用程序或文档的难度。 Microsoft推出了拖放绑定,但没有提及如何构建完整的应用程序。我很快就会转向MVVM,同时如果有人能指导我使用GREAT资源或功能完整的应用程序,即WPF,非MVVM和实体框架,我将非常感激。

相关问题