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

发布于 2024-10-15 05:40:47 字数 1932 浏览 1 评论 0原文

我想在 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(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 而不是我当前的技术,但我也无法完成这项工作。我们将非常感谢您的帮助。

I want to open a WPF4/EF4 form in AddNew mode so the user can start entering data in bound controls before any data has been selected from the database. I already have an "Add New Record" button but it only works with a populated DataContext (my CollectionViewSource). Here is the code so far:

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

Background: This is a basic WPF app with bound controls. I started with an Entity Framework model that appears in my DataSources window. I dragged my LabSample entity from the DataSources window and let it create my CollectionViewSource (labSamplesViewSource) in the XAML's Windows.Resources section. The DataContext for all my controls is the labSamplesViewSource. I create a new LabEntities object called _labEntitiesContext as the window is instantiated. I use _labEntitiesContext to build my filtered ObjectQuery(of LabSample) and to SaveChanges, but I'm a little confused as to how this _labEntitiesContext is hooked up to my CollectionViewSource. If you could clarify this along with answering my question that would be helpful. Note: I'm not ready to use MVVM.

When the window loads I use this.FindResource to grab a reference to the CollectionViewSource in a class level variable named _labSamplesCollectionViewSource. I allow the user to enter search fields to populate the screen with data. My LoadData routine looks something like this:

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;

The _labSamplesListCollectionView class level variable set above is used in my btnAddNewRecord_Click code. Before LoadData is called the _labSamplesListCollectionView is null causing my AddNew code to fail with "Object reference not set to an instance of an object".

How can I make this work? I'm wondering if I should be making use of _labSamplesListCollectionView.AddNew instead of my current technique but I couldn't get that work either. Your help will be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抹茶夏天i‖ 2024-10-22 05:40:47

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

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 可能有点大材小用。但是,如果它超过了几个视图,它将变得笨拙且难以来回移动数据并保持其最新且可维护。

MVVM Wiki 文章 - 一个非常好的起点和获取链接

这是我的 ViewModel 之一的构造函数。我知道您现在不想在 MVVM 中实现,但后面的代码会类似。在这种情况下,我使用后台工作程序来获取我的实体记录(构造函数调用就是为此而进行的,并且随后的视图设置可以忽略),然后我链接我的 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 是否为空,如果是,则创建它然后填充它。

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

I am writing an app that does something similar. I am however using MVVM pattern, which allows me to do some neat things. In mine, I am working with Shipments. On the ShipmentsView, I can click an "Add New" button which fires off a bound command property which is housed in the associated ViewModel class. That command methods looks like the following: Note: Views in this context are not CollectionView but refer to MVVM View classes.

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

My ShipmentView handles it's placement and visiblility, and my Shipment object has it's property values initialized so that it does not immediately present errors via it's validation handlers. This way the user can create a new shipment and if they get sidetracked they can save it and come back to it without having a bunch of mandatory fields.

When I use a CollectionViewSource, I populate it with an ObservableCollection of my entities, and then add the entities to that observable collection when I create them. ObservableCollection implements INotifyPropertyChanged and INotifyCollectionChanged events and notifies the UI when something happens, and it all works through the CollectionViewSource.

You might take a look at the MVVM pattern which is really good for moving data and keeping it in the proper scope, and there are some good MVVM frameworks out there that will help you make a nice application with MVVM.

MVVM may be a bit of overkill for your app if it is small. But if it gets over more than just a few Views it is going to get unwieldy and hard to move data back and forth and keep it current, and maintainable.

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

This is my Constructor for one of my ViewModels. I realize you don't want to implement in MVVM right now, but a code behind would be similar. In this instance, I am using a background worker to get my entity records, (the constructor call be for that and the View setting immediately afterward can be disregarded), then I link up my CVS, Populate it with my ObservableCollection, and set it's View to a field so I can filter on it later.

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

This is an example of my AddRecord method. Then I instance a new object, add it to the appropriate collection in the Context, Save it, execute a stored procedure, then refresh the context since the stored procedure did a few things to the record. Then I add the object to my 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

As for creating a new entity before your CollectionViewSource is created, a couple of questions. Is your edit forms datacontext related to the CVS? In my forms, the CVS is only used in conjunction with ItemsControls since it is displaying a collection of items. If your edit forms controls are dissociated from the CVS, you should not have much trouble populating them with a new entity and when it comes time to save, check to see if CVS is null and if so, create it then populate it.

If that is not a good answer, could you expand on how your application is structured?

断念 2024-10-22 05:40:47

当窗口加载或搜索未返回任何记录时,我会禁用所有数据输入控件,而不是在 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/实体框架数据绑定的标准参考应用程序或文档有多么困难感到失望。微软提倡拖放绑定,但没有给我们提供如何构建完整应用程序的参考。我很快就会转向 MVVM,同时如果有人可以指导我找到一个很棒的资源或功能完整的应用程序,即 WPF、非 MVVM 和实体框架,我将不胜感激。

Instead of opening the Window in AddNew mode I disable all data entry controls when the window loads or the when a search returns no records. When the "Add New Record" button is clicked I ALWAYS start over with a new data context that contains just one new entity. This means I have to prompt to save changes if any dirty (modified) records exist. The prompt allows the user to save changes, discard changes or continue editing (never entering AddNew mode). Here is the AddNew code:

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();

Here are my steps to put the window in AddNew mode:

1) Prompt to save changes.

2) Create a new entity and add it to my data context.

3) Create a new ObservableCollection of my entity type and assign it to the .Source of my CollectionViewSource. Note the _labSamplesCollectionViewSource is a reference to the XAML's CollectionViewSource that was auto-generated by dragging a table from the data sources window.

4) Assign the .View of the CollectionViewSource to a class level ListCollectionView variable.

5) Add the new entity to the ListCollectionView that was just created.

6) Call CommitNew and Refresh on the ListCollectionView

I have answered my own question here, but keep in mind that the answer is the result of trial and error and may not be ideal. Regarding my confusion as to how the _labEntitiesContext is hooked up to the CollectionViewSource I believe the answer is in the line that reads _labSamplesListCollectionView.AddNewItem(newEntity), but I'd like to see an explanation of how all of the objects reference each other.

My final comment/question is that I'm disappointed at how hard it is to find a standard reference application or document that teaches non-MVVM WPF/Entity Framework databinding in detail. Microsoft promotes drag-and-drop binding but leaves us without a reference on how to build a complete application. I'll move on to MVVM soon, meanwhile if anyone can direct me to a GREAT resource or feature complete application that is WPF, non-MVVM and Entity Framework I would greatly appreciate it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文