Returning an Empty Object to a DetailsView

Returning an Empty Object to a DetailsView

Old forum URL: forums.lhotka.net/forums/t/1374.aspx


mtavares posted on Tuesday, October 03, 2006

I was just wondering if there was a way to get the CslaDatasource to return what would be considered an empty data row to the detailsview.  I am trying to use the EmptyDataText  property on the Detailsview, and it appears that just passing my blank BO isn't good enough.  The Detailsview still thinks it is an actual data row instead of an empty one and therefore displays all of the fields with blanks instead of the EmpyDataText.  Is there something I have to do in the BO to tell the Detailsview it is actually empty?  Any help would be appreciated.

Thanks,
Mike

Jav replied on Tuesday, October 03, 2006

Try this.

Open DetailView --> Edit Templates --> Edit EmptyDataTemplate.  Then in the little window type something like "No data available"

I don't work with DetailViews but I do use FormViews and GridViews and it works in those.

Jav

mtavares replied on Tuesday, October 03, 2006

Hi Jav,

Thanks for the response.  Unfortunately, the problem for me is that the detailsview can't tell that my BO is empty, so it will never actually render what's in the EmptyDataTemplate.  I'm looking for a way to let the DetailsView know that the BO being passed into it is the equivalent of an empty data row.

Thanks,
Mike

Jav replied on Tuesday, October 03, 2006

Aah, now that I re-read your question I see that you were already trying to do what I was suggesting.  I assume that CslaDataSource in question is supposed to return an Object, not a Collection.  If that is the case, you are coming up against an issue which may require handling in the Factory method.

What happens is this.  You call your Shared Factory GetObject method. By the time the code gets to your DataPortal_Fetch, the object is already created with whatever values you assign to the object's instance variables.  (This is obvious because, after all, the DataPortal_Fetch is a method of that very object).  Now in DataPortal_Fetch when the call goes out to the database, it comes back empty handed, and you end up with your blank object back in the factory method, which is then returned to the UI.

I suppose what you would like to get back is "Nothing" or Null - in which case I expect that DetailView will show the EmptyDataView stuff.  You can achieve that by examining the object in the Factory method as it comes back from the DataPortal_Fetch for some key Instance variables - like the LastName being blank, and then return "Nothing" if that's the case.  Do make sure that your UI is aware of that and always checks for Nothingness of all such objects before trying to use them.

Jav

mtavares replied on Tuesday, October 03, 2006

So if I understand you correctly, if I determine the object passed back from my BO fetch to be a blank, then I should set the e.BusinessObject in the CslaDatasource to nothing.  Unfortunately, that doesn't seem to work.  I get the following error:

A data item was not found in the container. The container must either implement IDataItemContainer, or have a property named DataItem.

Let me know if I misinterpreted your suggestion. It seems like there needs to be some mechanism to tell the detailsview that the object I'm passing to it is empty, but still be a valid object.

Thanks,
Mike

Jav replied on Tuesday, October 03, 2006

Mike,

No, I was assuming that you have access to the Business layer, and I was simply trying to explain the reason why you are getting a "blank" object (instead of a Null object) when no data was found in the database, and how to return Nothing from the Factory Method. 

You cannot set CslaDataSource to nothing - that won't work as you already saw.  Normally, here is how you use the CslaDataSource.

    Protected Sub PersonDataSource_SelectObject(ByVal sender As Object, ByVal e As Csla.Web.SelectObjectArgs) Handles PersonDataSource.SelectObject
        Dim obj As Person = GetPerson()
        If obj IsNot Nothing Then
            e.BusinessObject = obj
        End If
    End Sub

So in effect, normally, you leave e.BusinessObject alone if the Object returned from CslaDataSource is Nothing. Possibly you could try doing the same thing if the object returned is "blank"

Jav

mtavares replied on Tuesday, October 03, 2006

I follow what you are saying, but even with the code that you just showed me, if your Person object is nothing and you don't set it to the datasource, you will still get the error because if e.BusinessObject is never set, it is still nothing and therefore the error I displayed earlier will still be thrown. 

I guess maybe the question I should be asking is how does the DetailsView know if something is a blank data row or not, and what can I do in my business object to make it think it is a blank data row.

Thanks,

Mike

Skafa replied on Tuesday, October 03, 2006

Concerncing the error message:
I've dealt with this before. The case is, when using CslaDataSource as the datasource on a *View Datasource / DataSourceID property, it tries to bind. And when it tries to bind, it expects a value. If it doesn't get a value, you get an error.

I'm not really into the internals of databinding or how rocky implemented CslaDataSource, but to avoid the error: do not databind if you know you have no object.

Jav replied on Tuesday, October 03, 2006

I just tried out a DetailsView for the first time. It lloks like:

So here is what I did:

In my quick test, I did not get any error, the Detailsview did not even show up - presumably because I did not set up EmptyData info.  I am assuming that when the object is valid, everything will show up.

Jav

mtavares replied on Tuesday, October 03, 2006

That is a workaround, but still doesn't get the detailsview to show the emptydatatext, it just doesn't display at all.  Upon some digging into the CslaDatasource,  I found a way to get it to work by changing some code in the ExecuteSelect Method.  The original code had the following:

         ' if the result isn't IEnumerable then
          ' wrap it in a collection
            If Not TypeOf result Is IEnumerable Then
                Dim list As New ArrayList
                list.Add(result)
                result = list
            End If


Now with the original code if result (the BO) is nothing, then when the control is bound to the detailsview that error occurs.  But if I change it to:

         ' if the result isn't IEnumerable then
          ' wrap it in a collection
            If Not TypeOf result Is IEnumerable Then
                Dim list As New ArrayList
                If result IsNot Nothing Then
                    list.Add(result)
                End If

                result = list
            End If

Then I get the results I was looking for.  the Details view will return the Empty Data Row because it is looking at an empty ArrayList instead of an arraylist with one item set to nothing.  I decided to test this same thing out with a collection based BO with a gridview, and the results were still good where the Empty Data Row for the gridview was displayed.  I also tried a bound dropdownlist and it was still ok.

So that being said, my next question if for Rocky:  Are there any repercussions with only adding the result to the list if it is not nothing?  My tests seemed to be fine, but I may not be accounting for something.

Jav replied on Tuesday, October 03, 2006

That's interesting.  Mike you may want to post this in a separate thread so that Rocky will see it.  That may be the answer to some of the tedious issues I have been facing with FormViews

Jav

Copyright (c) Marimer LLC