This is a migrated thread and some comments may be shown as answers.

CSLA Bindinglist with default objects

7 Answers 243 Views
GridView
This is a migrated thread and some comments may be shown as answers.
B
Top achievements
Rank 1
B asked on 18 Aug 2010, 08:39 AM
Hi,

I'm evaluating the Telerik GridView for use in a new project and am coming up against a couple of difficulties. I haven't found answers in the Forum, so I thought I would ask.

The situation. We are binding CSLA collections to a data grid. We want to use comboboxes for certain columns. Due to customer restraints, we are forced to use WinForms.

First. For GridViewComboBoxColumns. Is it possible to bind not to a value of the SelectedItem but to the item itself? We use readonly "Mini Objects" for things like Products and try not to expose the ID for that product. It shouldn't be necessary for the UI Developer to know what the ID is. You might think about adding the option SelectedItem to the ValueMember options. Then the SelectedItem is bound to the object and not the ID. I would think this would also be interesting for things like EF Entities where you also want to bind to an object and not directly to an ID.

I found a partial workaround for the above problem, see below, but it seems very cludgy.

 Private Sub RadGridView1_ValueChanged(ByVal sender As ObjectByVal e As System.EventArgsHandles RadGridView1.ValueChanged

        Dim dataRow As GridViewDataRowInfo = TryCast(Me.RadGridView1.CurrentRow, GridViewDataRowInfo)
        If dataRow Is Nothing Then
            Return
        End If

        Dim orderDetail As BO.OrderDetail = TryCast(dataRow.DataBoundItem, BO.OrderDetail)

        Dim cbEditor As RadDropDownListEditor = TryCast(Me.RadGridView1.ActiveEditor, Telerik.WinControls.UI.RadDropDownListEditor)

        If cbEditor IsNot Nothing Then
            Dim editorElement As RadDropDownListEditorElement = TryCast(cbEditor.EditorElement, RadDropDownListEditorElement)
            Dim prod As BO.ProductInfo = DirectCast(editorElement.SelectedItem.DataBoundItem, BO.ProductInfo)
            orderDetail.ProductInfo = prod
            orderDetail.UnitPrice = prod.UnitPrice
        End If
    End Sub


Second: Our Business objects are based on bindinglists. That means they have logic for determining default values for new items added to collections. For example for the OrderDetail object will automatically set the default discount depending on the Customer defined in the OrderObject.

Does the RadGridView support this kind of senario?  How can I convince the grid to use my 'correct' value instead of an empty version?

Also, since the RadGridView adds a "Phantom" object, the above code doesn't work. I can't set the editable price for the OrderDetail. It gets ignored.

Note, the default object works perfectly in the Windows datagrid but causes problems with the Telerik product. Interestingly, if I have both controls on the same form, bound to the same bindinglist and click on the "new row" in the Windows DataGrid, the Telerik gets all the events and shows the right information.

Thanks for any help.

7 Answers, 1 is accepted

Sort by
0
Julian Benkov
Telerik team
answered on 25 Aug 2010, 12:17 PM
Hello B,

Please accept my apologies for the delayed answer.

1) Currently RadGridView does not support this functionality out of the box. Please refer to the solution below. It demonstrates how to achieve the desired behavior using the ValueChanging event:

Public Partial Class Form1
    Inherits Form
    Public Class Product
        Public Property Id() As Integer
            Get
                Return m_Id
            End Get
            Set
                m_Id = Value
            End Set
        End Property
        Private m_Id As Integer
 
        Public Property Name() As String 
            Get
                Return m_Name
            End Get
            Set
                m_Name = Value
            End Set
        End Property
        Private m_Name As String
 
        Public Property Category() As Category 
            Get
                Return m_Category
            End Get
            Set
                m_Category = Value
            End Set
        End Property
        Private m_Category As Category
    End Class
 
    Public Class Category
        Public Property Id() As Integer
            Get
                Return m_Id
            End Get
            Set
                m_Id = Value
            End Set
        End Property
        Private m_Id As Integer
 
        Public Property Name() As String
            Get
                Return m_Name
            End Get
            Set
                m_Name = Value
            End Set
        End Property
        Private m_Name As String
    End Class
 
    Private comboColumn As GridViewComboBoxColumn
 
    Public Sub New()
 
        InitializeComponent()
 
        Me.radGridView1.ValueChanging += New ValueChangingEventHandler(AddressOf radGridView1_ValueChanging)
 
        Dim categories As New BindingList(Of Category)()
        Dim cat As New Category()
        cat.Id = 0
        cat.Name = "PC"
        categories.Add(cat)
        cat = New Category()
        cat.Id = 1
        cat.Name = "Laptop"
        categories.Add(cat)
        cat = New Category()
        cat.Id = 2
        cat.Name = "Phone"
        categories.Add(cat)
        Dim products As New BindingList(Of Product)()
        Dim product As New Product()
        product.Id = 0
        product.Name = "IBM"
        product.Category = categories(0)
        products.Add(product)
        product = New Product()
        product.Id = 1
        product.Name = "HP"
        product.Category = categories(1)
        products.Add(product)
        product = New Product()
        product.Id = 2
        product.Name = "HTC"
        product.Category = categories(2)
        products.Add(product)
 
        Me.radGridView1.DataSource = products
        Me.radGridView1.Columns.RemoveAt(2)
        'remove auto-generated Category column
        Me.comboColumn = New GridViewComboBoxColumn()
        comboColumn.DataType = GetType(String)
        comboColumn.DataSource = categories
        comboColumn.DisplayMember = "Name"
        comboColumn.FieldName = "Category.Name"
        Me.radGridView1.Columns.Add(comboColumn)
    End Sub
 
    Private Sub radGridView1_ValueChanging(sender As Object, e As ValueChangingEventArgs)
 
        Dim editor As RadComboBoxEditor = TryCast(Me.radGridView1.ActiveEditor, RadComboBoxEditor)
        If editor IsNot Nothing AndAlso Me.radGridView1.CurrentColumn = Me.comboColumn Then
            Dim element As RadComboBoxEditorElement = TryCast(editor.EditorElement, RadComboBoxEditorElement)
            Dim item As RadComboBoxItem = TryCast(element.SelectedItem, RadComboBoxItem)
            Dim cat As Category = TryCast(item.DataItem, Category)
            If cat IsNot Nothing Then
                Dim product As Product = TryCast(Me.radGridView1.CurrentRow.DataBoundItem, Product)
                product.Category = cat
            End If
 
            e.Cancel = True
            Me.radGridView1.CurrentRow.InvalidateRow()
        End If
    End Sub
End Class

2) RadGridView performs real adding operation in the underlying bound object after you press the 'Enter' key in the new row or change the focus to another row. You can use DefaultValuesNeeded event for your scenario to populate the default values.

I hope this information is useful. Let me know if you need further assistance.
Greetings,
Julian Benkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
B
Top achievements
Rank 1
answered on 26 Aug 2010, 10:44 AM
Hi Julian,

Thanks for your answer.

For question 1, I have a follow up. Why do you have the lines:
            e.Cancel = True
            Me.radGridView1.CurrentRow.InvalidateRow()
Is it correct that the e.Cancel overrides the original combobox behavior and the InvalidateRow call still allows row validation to fire?



Unfortunately 2 is a deal breaker. While I could set the default properties for the row I completely lose the business logic included in the object.

That means, for example, I have a a required field. My business object already handles that problem and returns the appropriate validation information. I can just bind my collection to the grid and it works. For your solution, I would have to completely redo that validation in the UI. Of course that validation should only fire if the current item is new.

There are of course other issues. For example, an order line item automatically calculates the current price dependant on the product price, quantity, tax, discounts and so forth. That logic is already included in the BO and sometimes can get very complex. Doubling that code in the UI would be ... um ... suboptimal.

You might consider allowing the user to override the AddNew behavior in future releases. An AddingNewRow event that lets the user set the new object. Life would be good. :-)

I'll have to think about a workaround. Is there a way to completely override the addnew row and replace it with a button? Then I could simply add the object myself. The problem is that the data entry should be mouseless if possible. Thus I'd like to replace the add new row with a button that gets tabbed to after the last column in the last row.

Thanks for your help.

0
Julian Benkov
Telerik team
answered on 31 Aug 2010, 01:38 PM
Hi B,

1) e.Cancel in ValueChanging event overrides the behavior only in the special case of a combo box column. All validation events will be processed with the default behavior for cells and rows.

2) If you want to override the operation of adding a new row in RadGridView, you can use the new event introduced in Q2 2010 - UserAddingRow - and cancel the adding operation if the new row is not valid in regards to your BO model and relations.

Sincerely yours,
Julian Benkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
B
Top achievements
Rank 1
answered on 01 Sep 2010, 04:57 PM
Thanks,

Unfortunately the UserAddingRow  fires too late. You have to have edited the row and click somewhere else before it fires. I would still have to rewrite all the business logic and validation use while the new row is being edited. That was my point.

Preferably you should handle the case where someone implements the IBindingList interface. That let's developers implement the AllowNew property and the AddNew method. The AddNew method should add the new object to the list and call the ListChanged Event. The ListChangedEventArgs give the properties ListChangedType and NewIndex. You can tell you are adding a new item and the object can be found in the list at the NewIndex location. Then bind to the newly added Item.

My BO's do this and in the normal Windows DataGrid the binding works normally.

Alternatively you would need a BeforeUserAddRow event with a NewItem Property in the Event Args. That way you could create the new object and return it. That would get added to the listview automatically. The user would write something like:

    Private Sub RadGridView1_BeforeUserAddRow(ByVal sender As ObjectByVal e As Telerik.WinControls.UI.GridViewBeforeAddNewRowArgsHandles RadGridView1.BeforeUserAddRow
e.NewItem = New OrderLineItem
    End Sub



0
Julian Benkov
Telerik team
answered on 07 Sep 2010, 11:18 AM
Hi B,

Thank you for writing me back.

Now I understand your scenario. In our previous versions we supported it. However, this behavior caused confusion in our users. It was not clear when the row is actually added in the data source and when in RadGridView. That is why we changed the behavior and now the row is added to the data source when the validation process finishes. Nevertheless, your scenario makes sense and we will consider extending our API to support both cases. 

If you have further questions, do not hesitate to contact me.

Regards,
Julian Benkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
B
Top achievements
Rank 1
answered on 08 Sep 2010, 11:21 AM
Ah. Now I understand.

Should I add this as a feature request?
0
Julian Benkov
Telerik team
answered on 13 Sep 2010, 03:24 PM
Hi B,

The issue has already been logged in our Issue tracking system. The new behavior and properties will be ready for the Q3 2010 release.

Thank you for you time.

Greetings,
Julian Benkov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
GridView
Asked by
B
Top achievements
Rank 1
Answers by
Julian Benkov
Telerik team
B
Top achievements
Rank 1
Share this question
or