Problem with serialization of objects that raise events handled by a non-serializable object (like a Windows Form)

Problem with serialization of objects that raise events handled by a non-serializable object (like a Windows Form)

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


PStanev posted on Monday, August 04, 2008

Problem with serialization of objects that raise events  handled by a non-serializable object (like a Windows Form)

I have  problem: (serializing objects that raise events when those events are handled by a non-serializable object (like a Windows Form). )The only diffence in my code is thet I dont use the standard EventHandler Because I have input parameteres. Here is my code:

<NonSerialized()> _

Private mNonSerializableSM As SMHandler

Private mSerializableSM As SMHandler

Delegate Sub SMHandler(ByVal Message As String, ByVal MessageType As MsgBoxStyle)

Public Custom Event SimpleMessageEvent As SMHandler

AddHandler(ByVal value As SMHandler)

If value.Target.GetType.IsSerializable Then

mSerializableSM = CType([Delegate].Combine(mSerializableSM, value), SMHandler)

Else

mNonSerializableSM = CType([Delegate].Combine(mNonSerializableSM, value), SMHandler)

End If

End AddHandler

RemoveHandler(ByVal value As SMHandler)

If value.Target.GetType.IsSerializable Then

mSerializableSM = CType([Delegate].Remove(mSerializableSM, value), SMHandler)

Else

mNonSerializableSM = CType([Delegate].Remove(mNonSerializableSM, value), SMHandler)

End If

End RemoveHandler

RaiseEvent(ByVal Message As String, ByVal MessageType As MsgBoxStyle)

If mNonSerializableSM IsNot Nothing Then mNonSerializableSM(Message, MessageType)

If mSerializableSM IsNot Nothing Then mSerializableSM(Message, MessageType)

End RaiseEvent

End Event

Everithing look right , but I still get the runtime error.

Please Help.

Thank You.

tetranz replied on Monday, August 04, 2008

I don't know why your code is not working but, just as a suggestion, the way I usually do this sort of thing is to use databinding, i.e, use the PropertyChanged event. It is already written and well debugged in CSLA. Databinding is the "official" way of communicating between an object and a form.

If you need to pass more information than just the fact that a property has changed then you can read other properties of your object in the event handler.

Ross

stefan replied on Tuesday, August 05, 2008

Hi,

I once solved this problem by implementing my own NonSerialized event inside my BO the following  way (sorry, C# Smile [:)]):

#region OnCriteriaEndEdit

        // A custom event to notify UI controls when EndEdit (=>AcceptChangesComplete) is called!
        [NonSerialized, NotUndoable]
        private EventHandler _onCriteriaEndEdit;

        public event EventHandler OnCriteriaEndEdit
        {
            [System.Runtime.CompilerServices.MethodImpl(
                System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
            add
            {
                _onCriteriaEndEdit = (EventHandler)Delegate.Combine(_onCriteriaEndEdit, value);
            }
            [System.Runtime.CompilerServices.MethodImpl(
                System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
            remove
            {
                _onCriteriaEndEdit = (EventHandler)Delegate.Remove(_onCriteriaEndEdit, value);
            }
        }

        protected override void AcceptChangesComplete()
        {
            base.AcceptChangesComplete();
            if (_onCriteriaEndEdit != null)
                _onCriteriaEndEdit (this, EventArgs.Empty);
        }

#endregion // OnCriteriaEndEdit

Stefan

dg78 replied on Sunday, October 12, 2008

Hi Rocky,

 

I have the same problem in vb.net.

I found this post in your blog :  http://www.lhotka.net/weblog/BetterVersionOfTheNET20EventserializationSolution.aspx

 

I code as you (or I think I do). In fact, I took the same code as event code in CSLA 3.5 (PropertyChanged / PropertyChanging / Saved ..).

 

Here my code in ucCustomer (user control in UI) and in Customer (in BLL).

 

-) in ucCustomer

 

  Private Sub myevent(ByVal sender As Object, ByVal e As EVZoneEventArgs) Handles mCustomer.ErreurValideZone

    MessageBox.Show(e.StrErreur)

  End Sub

 

-) in Customer

 

  <NonSerialized()> _

  Public _nonSerializableEVZHandlers As EventHandler(Of EVZoneEventArgs)

  Public _SerializableEVZHandlers As EventHandler(Of EVZoneEventArgs)

 

  Public Custom Event ErreurValideZone As EventHandler(Of EVZoneEventArgs)

    AddHandler(ByVal value As EventHandler(Of EVZoneEventArgs))

      If value.Method.IsPublic AndAlso (value.Method.DeclaringType.IsSerializable OrElse value.Method.IsStatic) Then

        _SerializableEVZHandlers = CType([Delegate].Combine(_SerializableEVZHandlers, value), EventHandler(Of EVZoneEventArgs))

      Else

        _nonSerializableEVZHandlers = CType([Delegate].Combine(_nonSerializableEVZHandlers, value), EventHandler(Of EVZoneEventArgs))

      End If

    End AddHandler

 

    RemoveHandler(ByVal value As EventHandler(Of EVZoneEventArgs))

      If value.Method.IsPublic AndAlso (value.Method.DeclaringType.IsSerializable OrElse value.Method.IsStatic) Then

        _SerializableEVZHandlers = CType([Delegate].Remove(_SerializableEVZHandlers, value), EventHandler(Of EVZoneEventArgs))

      Else

        _nonSerializableEVZHandlers = CType([Delegate].Remove(_nonSerializableEVZHandlers, value), EventHandler(Of EVZoneEventArgs))

      End If

    End RemoveHandler

 

    RaiseEvent(ByVal sender As System.Object, ByVal e As EVZoneEventArgs)

      If Not _SerializableEVZHandlers Is Nothing Then

        _SerializableEVZHandlers(sender, e) '.Invoke(sender, e)

      End If

      If Not _nonSerializableEVZHandlers Is Nothing Then

        _nonSerializableEVZHandlers(sender, e) '.Invoke(sender, e)

      End If

    End RaiseEvent

  End Event

 

 

Public Class EVZoneEventArgs : Inherits EventArgs

  Private mNumErreur As Integer

  Private mStrErreur As String

 

  Public Sub New(ByVal numErreur As Integer, ByVal strErreur As String)

    mNumErreur = numErreur

    mStrErreur = strErreur

  End Sub

 

  Public ReadOnly Property NumErreur() As Integer

    Get

      Return mNumErreur

    End Get

  End Property

 

  Public ReadOnly Property StrErreur() As String

    Get

      Return mStrErreur

    End Get

  End Property

End Class

 

The issue during the run time appends in CSLA in BinaryFormatterWrapper.vb :

 

    Public Sub Serialize(ByVal serializationStream As System.IO.Stream, ByVal graph As Object) _

      Implements ISerializationFormatter.Serialize

      _formatter.Serialize(serializationStream, graph)

    End Sub

 

To test, I put breakpoints and I go step by step.

I saw that  _nonSerializableEVZHandlers is used.

 

If I put a comment before _formatter.Serialize(serializationStream, graph) then the UI consume the event but .. it is not good because I change CSLA and there is no serialization.

 

If I put a comment in the event code in the UI and  no comment before _formatter.Serialize, I have no runtime error

 

I don't understand where is my mistake.

 

Thanks for your help.

 

Dominique

 

PS: to Ross (tetranz) : I think that databinding is "a" way of communicating between an object and a form. But it is not the only way, sometimes it is useful to use an event.

To Stefan : I am sorry but I don't use C#  Smile [:)]

dg78 replied on Tuesday, December 09, 2008

*bump*

 

I reactivate this thread because I didn't have an answer.

During this time, I put a comment before _formatter.Serialize(serializationStream, graph) in Csla (BinaryFormaterHelper.vb) but it is not a solution.

 

I use now Csla vb 3.52 and I have always the same problem.

 

I use in a BO class, the same code there is in Bindable.vb.

 

I can see (with breakpoints and step by step) that_nonSerializableEVZHandlers is used for the AddHandler to define the event.

 

The problem is in  _formatter.Serialize(serializationStream, graph) if graph include _nonSerializableEVZHandlers. It want serialize the user control.

 

I test without _nonSerializableEVZHandlers and it is good.

 

Thanks for help.

 

dg78 replied on Tuesday, December 09, 2008

I think that I found the solution :

If I add  in my code :    <NotUndoable()> _    it is OK :

 

  <NonSerialized()> _

  <NotUndoable()> _

  Public _nonSerializableEVZHandlers As EventHandler(Of EVZoneEventArgs)

  <NotUndoable()> _

  Public _SerializableEVZHandlers As EventHandler(Of EVZoneEventArgs)

 

Rocky, you use this code in 4 places in Csla.

 

Two with  <NotUndoable()> _    :   BusinessBase.vb and BusinessListBase

 

Two without  <NotUndoable()> _    :  Bindable.vb and ExtendedBindingList.vb

 

Is it normal ?

Copyright (c) Marimer LLC