CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • CSLA4: Windows .Net

    rated by 0 users
    Not Answered This post has 0 verified answers | 8 Replies | 1 Follower

    Top 50 Contributor
    168 Posts
    gajit posted on Sun, Feb 19 2012 8:47 AM

    OK, I've managed to successfully write a quick EditPerson form for Windows Forms using CSLA4.2.2 - so I'm now making progress.

    I'm using the EncapInvoke model.

    My first test was using a MockDb and I am able to list, edit and add new records in my person "table".

    So, my next step was to create the DataAccess layer for a SQL Server Express implementation - as this is my core development background.

    Everything works - until I try to Save a changed, or new record. I get an exception;

    System.InvalidOperationException = {"Object is still being edited and can not be saved"} StackTrace = "   at Csla.BusinessBase`1.Save() in C:\Visual Studio Projects\csla\40\Source\Csla\BusinessBase.cs:line 126     at Intro.EditPerson.SaveRecord(Boolean rebind)"

    Any ideas? The code in the client is exactly the same regardless of the Dal I'm using, so I'm thinking the issue lies within CSLA rather than my code... but I'm sure someone would have heard of it by now?

    This is my "SaveRecord" code:

    Private Sub SaveRecord(ByVal rebind As Boolean)

            Using busy As New StatusBusy("Saving...")
                ' stop the flow of events
                Me.PersonEditBindingSource.RaiseListChangedEvents = False

                ' do the save
                Dim temp As PersonEdit = mPERSONEDIT.Clone
                temp.ApplyEdit()

                Try
                    mPERSONEDIT = temp.Save '<------------- error's at this point
                    PersonEdit.BeginEdit()
                    If rebind Then

                        ' rebind the UI
                        With Me.PersonEditBindingSource

                            .DataSource = Nothing
                            .RaiseListChangedEvents = True ' this is the key to updating children

                            .DataSource = mPERSONEDIT

                        End With

                        ApplyAuthorizationRules()
                    End If

                Catch ex As Csla.DataPortalException
                    MessageBox.Show(ex.BusinessException.ToString, _
                      "Error saving", MessageBoxButtons.OK, _
                      MessageBoxIcon.Exclamation)

                Catch ex As Exception
                    MessageBox.Show(ex.ToString, _
                      "Error saving", MessageBoxButtons.OK, _
                      MessageBoxIcon.Exclamation)

                Finally
                    Me.PersonEditBindingSource.RaiseListChangedEvents = True
                End Try

            End Using

        End Sub

     

    Feedback would be appreciated.

     

    Thanks,

    Graham

     

     

     

    All Replies

    Top 10 Contributor
    2,279 Posts

    You must unbind the object completely from the UI. This is described in Rocky's books.

    And you do not have to make a clone in your code - this is done automatically by CSLA DataPortal.

    These extensions is translated from CslaContrib to vb.net:

    Public NotInheritable Class BindingSourceExtensions
        Private Sub New()
        End Sub
        ''' <summary>
        ''' Unbind the binding source and the Data object. Use this Method to safely disconnect the data object from a BindingSource before saving data.
        ''' </summary>
        ''' <param name="source">The source.</param>
        ''' <param name="cancel">if set to <c>true</c> then call CancelEdit else call EndEdit.</param>
        ''' <param name="isRoot">if set to <c>true</c> this BindingSource contains the Root object. Set to <c>false</c> for nested BindingSources</param>
        <System.Runtime.CompilerServices.Extension> _
        Public Shared Sub Unbind(source As BindingSource, cancel As Boolean, isRoot As Boolean)
            Dim current As IEditableObject = Nothing
            ' position may be -1 when bindigsource is already unbound
            ' and accessing source.Current will then throw Exception.
            If (source.DataSource IsNot Nothing) AndAlso (source.Position > -1) Then
                current = TryCast(source.Current, IEditableObject)
            End If

            ' set Raise list changed to True
            source.RaiseListChangedEvents = False
            ' tell currency manager to suspend binding
            source.SuspendBinding()

            If isRoot Then
                source.DataSource = Nothing
            End If
            If current Is Nothing Then
                Return
            End If

            If cancel Then
                current.CancelEdit()
            Else
                current.EndEdit()
            End If
        End Sub

        ''' <summary>
        ''' Rebind the binding source and business object.
        ''' </summary>
        ''' <param name="source">The source.</param>
        ''' <param name="data">The data object.</param>
        <System.Runtime.CompilerServices.Extension> _
        Public Shared Sub Rebind(source As BindingSource, data As Object)
            source.Rebind(data, False)
        End Sub


        ''' <summary>
        ''' Rebind the binding source and business object.
        ''' </summary>
        ''' <param name="source">The source.</param>
        ''' <param name="data">The data object.</param>
        ''' <param name="metadataChanged">if set to <c>true</c> then metadata (type) was changed.</param>
        <System.Runtime.CompilerServices.Extension> _
        Public Shared Sub Rebind(source As BindingSource, data As Object, metadataChanged As Boolean)
            source.RaiseListChangedEvents = True
            source.SuspendBinding()

            If data IsNot Nothing Then
                source.DataSource = data
            End If

            ' set Raise list changed to True
            source.RaiseListChangedEvents = True
            ' tell currency manager to resume binding
            source.ResumeBinding()
            ' Notify UI controls that the dataobject/list was reset - but metadata was not changed
            source.ResetBindings(metadataChanged)
        End Sub
    End Class

     

    So you save code should be something like this:

           Using busy As New StatusBusy("Saving...")
                ' unbind from bindingsource
                Me.PersonEditBindingSource.Unbind(False, True)

     

                Try
                    mPERSONEDIT = mPERSONEDIT .Save

                    .......
     and make sure to rebind your bo before you leave the method:

                Me.PersonEditBindingSource.Rebind(mPERSONEDIT)

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 50 Contributor
    168 Posts
    gajit replied on Sun, Feb 19 2012 10:32 AM

    Just when I thought I was getting to grips...... that's confused me completely.

    My code was working code for CSLA2.1 - and now it's breaking code? You'll excuse me if I missed whatever reference was made to unbinding an object - but there was no WindowsForms book - and as this code previously worked, you'll understand why I'm not clear that it no longer works.

    There is no Unbind method for the .Net BindingSource - how is that implemented in my .Net code?

    I don't understand why it would be worrking code for one Dal and not another...

    My form currently inherits from what was previously WinPart in the CSLA implemetation. Are you saying there is a new helper control that I should be inheriting from?

    Graham

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Sun, Feb 19 2012 12:01 PM

    Unbind/Rebind is implemented in the BindingSourceExtensions in my previous post.

    Binding/Unbinding is described in the Using CSLA 3.0 ebook - also available for VB.

    I also have a blog post on Bind/Rebind here:
    http://jonnybekkum.wordpress.com/2009/10/20/forms-databinding-the-magic-sequence-of-binduiunbindui/

     

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 50 Contributor
    168 Posts
    gajit replied on Sun, Feb 19 2012 5:26 PM

    Thanks Jonny.

    I downloaded the WfUI from SVN as discussed in a previous post and it shows clearly the implementation - thanks.

    I do have an issue with Closing a Winpart...

    In say my PersonEdit (Winpart) form, I close The form,

    But when the Mainform tries to close the Winpart, it blows up on:

         Private Sub CloseWinPart(ByVal sender As Object, ByVal e As EventArgs)

            Dim part As WinPart = DirectCast(sender, WinPart)
            RemoveHandler part.CloseWinPart, AddressOf CloseWinPart
            part.Visible = False
            SplitContainer1.Panel2.Controls.Remove(part) '<----- Blows up here

            part.Dispose()

    "Cannot bind to the property or column Id on the DataSource.
    Parameter name: dataMember"

     

    I can alleviate that issue by Rebinding after all events - such as Save and Close - which I would normally just close the form - that's what I used to do in CSLA2.x.

    Is this normal or is there something I need to do before Closing the form, without rebinding?

    Thanks,

    Graham 

    Top 10 Contributor
    2,279 Posts

    Most likely caused by the Items collection being active in databinding on a ComboBox.

    I recommend  to unbind combobox items after <bo> i unbound and rebind items before rebind of  <bo> .

     

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 50 Contributor
    168 Posts
    gajit replied on Mon, Feb 20 2012 11:02 AM

    I wish it was tjhat simple.

    The form comprises 2 textboxes and some buttons...

     

    G.

    Top 10 Contributor
    9,475 Posts

    gajit:

    I can alleviate that issue by Rebinding after all events - such as Save and Close - which I would normally just close the form - that's what I used to do in CSLA2.x.

    I think the challenges you are facing are due to changes made in 3.0 (2006 or so) designed to highlight bugs in Windows Forms UI code around binding and unbinding.

    I made those changes because without them, most UI code was wrong, and nobody knew it was wrong other than many people's programs would "randomly" fail.

    I fully appreciate your frustration. A whole lot of people have hit these same challenging issues over the past several years since 3.0 came out.

    The core rule is simple: you must unbind your object graph from the UI before manipulating it in code.

    Windows Forms data binding assumes total ownership of the object graph as long as it is bound. I fought that, and fought that, but ultimately just couldn't win. So all we can do is live with the reality.

    Sadly, unbinding isn't trivial (unless you have just a single object). This is because you must understand and accommodate the way Windows Forms data binding handles currency. Every binding source has currency, and whatever object is current will have an elevated edit level. It is up to you to lower that edit level after unbinding.

    To make that more "fun", there are differences between parent and child binding source objects.

    All this is detailed in the Using CSLA .NET 3.0 ebook in some detail.

    The Expert 2008 Business Objects book has some content that discusses some helper types we added to the framework around the year 2008 to help ease this unbinding process.

    I do plan to update the WfUI project to use those helpers when I get time, but I haven't done WinForms work for a few years, so I need to relearn how all that stuff works myself...

    Just at the moment I'm in the middle of a bunch of travel for work, the 4.3 release, and some potentially very serious family health issues. If the health issues take a bad turn (which sadly seems likely) I may go dark for some time to deal with everything involved.

    In other words, don't hold your breath for the WfUI changes - the existing code may have to suffice.

    Rocky

    Top 50 Contributor
    168 Posts
    gajit replied on Tue, Feb 21 2012 6:55 AM

    Thanks Rocky - I appreciate you taking the time to explain.

    I have the 2008 book so I'll have a quick scan over that. I think my UI code probably originated from the 2005 book, so it could probably do with freshening up anyway.

    It is frustrating, but I'm sure I'll get there - I've made significant progress in the last week with your help and Jonny's, so I'm confident I'll be "off to the races" very soon.

    I wish you well with the family health issues - I don't think anyway would expect you to do anything else.

    Thanks again,

    Graham

    Page 1 of 1 (9 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems