0

I'm trying to build a data entry form in wpf. To perform validation I apparently need to have an object attached in the datacontext of my grid. But how can I have one when I didn't create one yet?

How does it work?

For example, I have a screen with a datagrid. The datagrid contains users that were obtained from membership. Above the grid is a button: add user. When clicked a new window appears and the following can be entered: user name, password, email. To perform validation on the textboxes to see if they aren't empty. Now, it is my understanding that the way this works is by having an object attached to the window (datagrid datacontext). But how can I have it attached when it doesn't exist yet?

Garth Marenghi
  • 1,997
  • 5
  • 20
  • 38

4 Answers4

2

This is a case where MVVM design patterns are very useful.

Every WPF view has a corresponding view model object that the properties in the view are bound to. So your window with the data grid has a view model - its DataContext - and the view model has properties that are bound to properties in the view - e.g. the ItemsSource in the data grid is bound to a collection (see note 1).

The "add user" command (which is implemented as a RelayCommand in the window's view model) creates a new view (the new window) and its corresponding view model object (the new user), sets the view's DataContext to the view model, and calls ShowDialog to show the window. (See note 2.) If the user accepts the new object, ShowDialog returns true, and the logic in the command takes the view model object (which now contains whatever changes the user made) and uses the information in it to create a new model object and add it to the model. If the user cancels, ShowDialog returns false, and the command discards the view model object without creating a new model object.

Note 1: The collection here may be a collection of model objects, or it may be a collection of view model objects. It depends on whether or not you need anything that's not in the model for displaying the model objects in a data grid. It's common, in this kind of scenario, for the objects in the grid to be view models for the dialog - that is, the view model objects have properties implemented for both display in the grid and modification in the dialog window. On the other hand, if all the grid is doing is displaying data from the model, there may be no need for an intermediary object.

Note 2: Having the command create a WPF window violates a central MVVM design principle, which is that view models shouldn't create WPF objects. The reason for this principle is pretty simple: you can't build an automated unit test for this command, since it's just going to throw up a dialog and wait. There are all kinds of different approaches to this - see, for instance, this question, and Josh Smith's blog post on the Mediator pattern - and all of them involve delegating the creation and display of the actual dialog window to a separate service that can be mocked out for unit testing. If you don't want to choose one of those approaches up front, you can retrofit one into your application once you get this thing working.

Community
  • 1
  • 1
Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
0

The idea here is that you should attach an object which is slightly different from your business models. In your case it won't UserInfo (or whatever you have for users in grid). It will be some other class, more suitable for editing. In MVVM this class will be a ViewModel. This class will have some differences comparing to your regular user class, for example it may have some properties nullable (when you haven't set them yet). Also this class will handle validation. You should instantiate this class at the same time you're creating an editor window and put instance of this class into Window.DataContext.

Snowbear
  • 16,924
  • 3
  • 43
  • 67
  • Aha. This is interesting! I was (still am a bit) confused of how this thing should work. I just wanted to have a form that had some fields, fill in the data, then -> database. I was getting raised eyebrows for this and I heard that the datacontext needed to be filled. I didn't understand because I just didn't have an object (or so I thought) to bind to the datacontext. – Garth Marenghi Mar 18 '11 at 13:23
0

Hmm, there is a lot in this question but I just created a screen with three data grids (I am using Telerik in this case) and under each datagrid is a button to add to the grid. No the window with the three datagrids has it's own view model. and each of the "pop up's" has it's own viewmodel, in this case all of these are user controls and I just create a new window and set window.content and call show dialog.

Communication is facilitated via "events" - not the standard events you are used to in .NET but in this case I am using Prism and it's CompositePresentationEvent class. When the user is done creating their new object they click add and I fire off this event with the "payload" being the object they created. The main window with the three grids listens for that event and has a method to handle it, in this case adds it to the ObservableCollection which is what I bind the grids to.

If I were you I would look into the various frameworks that are out there, Prism, MVVM light etc... Again, your question seemed rather broad, I tried to give an overview but I didn't go into detail, if you look into some sort of framework I think it will clear up a lot of these details for you.

Kenn
  • 2,709
  • 2
  • 29
  • 60
  • Okay, maybe I should formulate it differently: When clicking an add button that pops up a new window in which you can enter e.g. a new user, the datacontext of (for example) a grid in the new window which contains those fields should be bound to the object for which you are filling in the fields, right? I actually just wanted to know if I'm right with the assumption that an empty object should be bound to the window when filling in a form for oh, let's say a new product or user. – Garth Marenghi Mar 18 '11 at 13:20
0

When the users hit Add New, create a new blank copy of your object, and set the datacontext to that new object.

Set some kind of flag to identify that it is a New object. This can be the Id being NULL, 0, -1, etc or an ObjectState property set to New. That way all your validation rules apply, and once the user hits save you know to INSERT instead of UPDATE

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Yes, maybe something like this. The reason being so that I can validate the user input. I at first was looking for something like asp.net's validator controls, but they don't exist in wpf. Trying to figure out how to validate for empty textboxes, people kept saying I needed to have my datacontext set. – Garth Marenghi Mar 18 '11 at 14:08
  • Usually the object you are binding your DataContext to will implement `IDataErrorInfo` and this allows you to write some validation code for your class that is automatically picked up by WPF. So the validation exists in the Object that is being bound to, not within the UI controls. – Rachel Mar 18 '11 at 15:01