Hi,
I'm trying to use CSLA with the DataGrid control but have hit a snag when it comes to Undo and more specifically Model.CancelEdit().
After a call to Model.BeginEdit(), I Add a new row to the DataGrid, then Edit a DataGridTextColumn, followed by cancelling the action with Model.CancelEdit();
This causes an "Edit Level Mismatch in UndoChanges" exception.
Editing a DataGridTemplateColumn does not cause this behaviour
Is there a solution to this other than having to use DataGridTemplateColumns for each column?
Regards
What version of Csla are you using?
Im using 4.1.0.
On further searching, this looks simliar to a issue brought up in the forum back in 2009 before the DataGrid was released and was part of the WPFToolkit.
http://forums.lhotka.net/forums/p/7033/33676.aspx#33676
I've traded emails with at least one of the guys who own that control at Microsoft, so they are aware that the control doesn't act properly - or at least is unique in its behavior when compared to Windows Forms or Silverlight controls.
I suspect it would be helpful for you (and anyone else who cares) to report these issues on connect.microsoft.com as well, so there's community pressure to fix the control.
Hi Rocky,
I've had a look on the connect website to see if this has been posted before and it hasn't. I'd log the issue on there, but without wanting to sound foolish im not sure i could give enough detail on the problem as I don't fully understand what specifically is lacking with the DataGrid and what it "should" be doing.
Regards
David
Here is some specific detail (copied from an email):
My continual challenge with the WPF datagrid is that it isn’t 100% compliant with the way the Windows Forms or Silverlight datagrids interact with the various data binding interfaces and events.
Since my CSLA 4 base classes provide consistent support across all three platforms (and WP7, but there’s no datagrid there), it is problematic when the WPF datagrid doesn’t operate in a way that is consistent with the other smart client UI technologies.
Though it is also possible that WPF is requiring some extra interface or nuance I’m missing – that’s also possible.
Issues:
1. The datagrid doesn’t use the AddNew method to add new items to a collection, nor does there appear to be a way to customize how the new object is created – the datagrid requires a public default constructor – this is non-workable in many business scenarios – the WinForms and SL datagrids either honor the AddNew mechanism or have a way to customize how new items are created
2. The datagrid doesn’t properly invoke the IEditableObject interface if it is implemented by the items in a collection – most notably, the EndEdit method isn’t invoked when the user successfully leaves or deletes a row, so the item doesn’t know that the user is done editing the item
The first issue is a globally bad thing for pretty much all collections.
The second issue is a problem for CSLA, because I rely on proper use of IEditableObject to manage elements of state within objects. One common scenario that fails is a type of collection I have where changes the user makes in a datagrid are automatically committed as the user leaves each row. Since there’s no way to detect when a user has left a row in the WPF datagrid this collection type fails in WPF.
It works great in Silverlight and Windows Forms, where IEO is invoked correctly.
Ok, Thanks Rocky for the details.
I'll submit a post to the connect website and link this thread to it.
Regards
David
Two questions:
#1: It's been another two months. I want to create a standard template for all projects going forward but this buggy datagrid is a real issue. Has anything happened with it since the bugs have been reported?
#2: How are people working around these bugs? I currently comment out "AddNewCore()" and I include MarkAsChild() in the constructor of the child objects. Is this advisable? Thoughts?
My stars, when I use the WPF grid NewChild isn't even called. Am I really limited to initializing my new child object inside the default constructor? Tell me this isn't true. Does the DataGrid completely bypass the DataPortal?
The standard WPF datagrid does not implement standard data binding behaviors, no. This makes it really hard to use against any source objects (like CSLA objects or the DataTable) that expect standard binding behaviors. I've reported this to the team a couple times, but they don't seem inclined to fix the issues.
Never got round to posting on connect as Im working on something else at present, apologies for that.
Here's the post if anyone want to "vote" to increase its importance or add to content.
https://connect.microsoft.com/WPF/feedback/details/675473/wpf-datagrid-add-new-behaviour-and-ieditableobject-invocation
Hi
The guys from connect have asked for a repro. This is fair enough, I've tried recreating a small sample, however this project does not reproduce the error, it just works which is frustrating!!
see my sky drive for sample.
http://cid-044ad885bcfe52a6.office.live.com/self.aspx/.Public/DataGridTest.rar
Referring back to my initial issue, I managed to get the error to disappear in my company's application if do either of the following;
1.I remove "UpdateSourceTrigger=PropertyChanged" from my DataGridTextColumn binding expression.
2.Use a DataGridTemplateColumn with a TextBox as the template.
Has/Can anyone else repro this error? The bug will be closed off on connect if this can't be reproduced.....
Regards
David
The standard WPF datagrid does not implement standard data binding behaviors, no. This makes it really hard to use against any source objects (like CSLA objects or the DataTable) that expect standard binding behaviors. I've reported this to the team a couple times, but they don't seem inclined to fix the issues.
Which "standard data binding behaviors" are you talking about? The WPF 4.0 DataGrid supports IBindingList.AddNew and IEditableObject.EndEdit, at least in all the samples I'm aware of. It works with DataTable. It works with INotifyCollectionChanged and INotifyPropertyChanged. It works with IBindingList. There are bugs, but not of the magnitude you're citing. Please explain.
Also, I've looked around for your "reports to the team", but I can't find them. Can you help me? Do you have bug numbers, emails, titles, other identifying info?
- Sam (WPF team)
Hi Sam, thanks for jumping in, I appreciate it.
I think there are two broad areas.
First, a collection can't implement IBindingList and also be an ObservableCollection. This is a broader issue than the datagrid control, but it is really ugly. To play well with much of WPF a collection should be an ObservableCollection, but to play with certain controls (apparently including the .NET 4 datagrid) the collection needs to be a BindingList. Nasty! (Most of my testing over time has been with ObservableCollection types, with the assumption that BindingList was a dying type. This has been part of my frustration.)
Second, if we restrict the conversation to BindingList subclasses, the behavior of the datagrid is somehow pretty different from the WinForms equivalent.
Specifically for point 2 though - I'm just plain confused about what is going on.
When EndEdit is called, my object handles that call by telling the parent collection to save the now-edited child object. This causes the collection to find the child object in the collection - but it isn't there. In fact, at this point I can look in the collection and see the unedited items - so clearly the datagrid is manipulating some sort of copy or clone of the actual item.
That's very uncool...
1. You don't need to move focus. Type Enter - that commits the row. Or type Ctrl-Enter - that commits the row and leaves it selected.
2. DataGrid doesn't clone anything. It calls IEO.EndEdit on the actual item it's editing.
3. DEL removes the selected row, provided it isn't in edit mode. To leave edit mode, type Enter (to commit) or ESC (to cancel). You may need to ESC twice - once to leave cell-edit mode, and once to leave row-edit mode. The DEL should work.
I sympathize with your confusion. I'm also confused - the things you're trying to do work just fine for me (using ADO.net DataTable), modulo the little suggestions. I don't understand (2) at all - I don't see anything resembling what you do. That's why a repro would help, in case there's some oddity about your particular BindingList that we don't handle.
The only quirk about BindingList (vs. ObservableCollection) I've seen mentioned so far is the AddNew issue. Is there more?
The AddNew issue is a dropped ball on our part. In 4.0 we added IEditableCollectionViewAddNewItem to ListCollectionView, specifically to support the operation of "add an existing item to the collection". The app creates the new item any way it likes, then calls AddNewItem to add it to the collection. This was a request from the DataGrid feature team, but then they neglected to add anything to DataGrid to take advantage of it. I'll see whether it's possible to get that added for the next release. We all agree it's necessary.
Thanks for all that info - it is very helpful.
Based on what you are saying, I have continued to try and figure out what is happening with #2. As a result I have a question.
Here's what is happening:
This works the first time the user edits a row, and fails on subsequent tries - at step 3, because the item isn't actually in the list - the datagrid is editing a copy of the item.
I wonder if the datagrid control is operating against a view over the list, and not the list itself? And perhaps that view over the list isn't being updated based on that ListChanged event? So the datagrid control ends up editing a stale copy of the object, and not the one that's actually in the list?
This stuff is, of course, incredibly hard to debug. But my observation matches what I'm describing here (or so I think).
I can provide a repro, no problem. It includes the CSLA source code, because all the relevant code is in the interplay between the list base class and editable object base class in the CSLA framework. And that's not a problem from a repro perspective either, other than that CSLA is non-trivial.
Please send me a repro.
DataGrid talks to the collection through a collection view (presumably BindingListCollectionView), but the view should be reacting to ListChanged events and keeping up to date. You describe a re-entrant scenario - the ListChanged is happening while DataGrid is committing the row - which could be causing problems. I'm not sure how the various pieces handle re-entrancy, but a repro will help clarify.
Which class implements IBindingList here? Is it a CSLA class, a Microsoft class, or the app's class?
IBindingList is implemented by Microsoft's BindingList<T>, and my CSLA classes subclass BindingList - with the business class subclassing a CSLA base class.
Yes, the scenario is reentrant, and I'll put together a repro. As you might expect, this behavior has existed for many years in the WinForms world, but there's no guarantee the WPF datagrid matches the WinForms one. The SL datagrid does work as expected - but I'm guessing there's little code-sharing between WPF and SL for the datagrid because they are so different in other ways.
Then again, in SL the collection is a subclass of ObservableCollection, because there is no BindingList, so that could be an important difference too.
The reentrancy (adding/removing from the collection in response to IEO.EndEdit) comes from CSLA classes, right? BindingList<T> doesn't do that on its own.
How do you add a new item in SL? Like WPF, the SL DataGrid doesn't have any AddNew functionality that lets the app construct the new item. Yet you say that SL DataGrid works for you. What's different vs. WPF?
Also, I'd like to amend a previous remark. The WPF DataGrid team didn't "drop the ball" on the AddNew functionality. They tried to do it, but it didn't happen for a variety of non-technical reasons (schedule constraints, priorities, etc. etc.). From your point of view, that's no help - the necessary feature is missing, and who cares what the reason is. But I didn't mean to dis my friends down the hall :).
Rocky, do you have any more thoughts on this issue. I realise this thread has been time consuming for you and apologise for that since its not directly a CSLA issue, however the bug on connect is soon to be closed off as "Cannot Repro".
Regards
David
I have a repro I need to package up and send to Sam. The challenge is that I'm on vacation, and so have been trying to sneak bits of CSLA work in between normal vacation activities :)
The bug on connect has now been closed off.
Will have to log the issue from scratch with a repro if we want the IEdiatbleObject issue looked at again.
Copyright (c) Marimer LLC