IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

Récupération d'évènement entre assemblys différentes


Sujet :

Windows Forms

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 92
    Points : 114
    Points
    114
    Par défaut Récupération d'évènement entre assemblys différentes
    Bonjour,

    je developpe un mini framework d'interface et je rencontre un problème que je ne m'explique pas...

    J'ai trois assemblys: Une pour la GUI, une embarquant les classes métiers et mon framework.

    Ce framework intègre une classe générique qui hérite de Collection<>. Lorsque je demande à supprimer un objet, ma couche métier lance un évènement qui est trappé dans ma collection générique qui elle même lance un autre évènement pour que l'interface graphique affiche un message de confirmation. Et c'est là que ca coince:

    L'évènement n'est jamais récupéré par l'interface graphique. La chaine s'arrête dans ma collection générique.

    Après debug, au moment ou l'on entre dans la collection pour supprimer un élément de la collection, j'ai bien un abonné à mon évènement. Au retour, (c'est à dire quand on récupère l'évènement dans la classe collection), l'objet se comporte comme s'il était différent: Plus d'abonné à l'évènement et là où ca devient plus bizarre, c'est que les deux objets (la collection à laquelle on supprime un élément et celle qui récupère l'évènements) sont différents alors qu'à aucun moment on ne repasse dans le constructeur de la collection .

    Là ou les choses deviennent encore plus bizarres, c'est que si j'intègre ma classe collection générique dans l'assembly métier, tout marche bien .

    A priori tout est bien cablé (références etc.)...

    Merci à ceux qui auront le courage de lire et un très grand merci d'avance pour votre aide.

  2. #2
    Membre éclairé
    Inscrit en
    Octobre 2006
    Messages
    587
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2006
    Messages : 587
    Points : 706
    Points
    706
    Par défaut
    Tu peux nous montrer un bout de code ?

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 92
    Points : 114
    Points
    114
    Par défaut
    Je mets ce qui me semble être le plus significatif mais c'est un peu tordu je préviens

    Dans mon assembly framework:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
     
     
     public class ConnectedCollectionBase<T> : BindingList<T>, IMessageSender<T> where T:IRuleable<T>,IBindableObject
        {
            private Guid? toto = Guid.Empty;
     
            public Guid? Toto
            {
                get
                {
                    if (toto.Equals(Guid.Empty))
                        toto= Guid.NewGuid();
     
                        return toto;
                }
            }
     
            /// <summary>
            /// Event to fire a message to a GUI.
            /// </summary>
            public event EventHandler<MessageEventArgs<T>> MessageSend;
     
            /// <summary>
            /// Method implemented to raise the MessageSend event.
            /// </summary>
            /// <param name="e">The argument passed when firing the event.</param>
            public virtual void OnMessageSend(MessageEventArgs<T> e)
            {
                if (MessageSend != null)
                    MessageSend(this, e);
            }
     
             /// <summary>
            /// Removes an item from the collection. The method is called when deleting an item from a binded control for instance.
            /// </summary>
            /// <remarks>The item is only removed if the call to the delete method of the underlying object succeeds.</remarks>
            /// <param name="index">The index of the item that is deleted.</param>
            protected override void RemoveItem(int index)
            {
                if (this.Items[index].Delete(true))
                {
                    IMessageSender<T> rules = this.Items[index].Rules as IMessageSender<T>;
     
                    if (rules != null)
                    {
                        rules.MessageSend -= new EventHandler<MessageEventArgs<T>>(ObjectRules_SendMessage);
                        base.RemoveItem(index);
                    }
                }
            }
     
            /// <summary>
            /// Method called when a property of an item of the underlying connection occures.
            /// </summary>
            /// <param name="e">Parameter to know which action was made.</param>
            ///<remarks>The items are inserted only when an item is added and can be inserted in the underlying store.
            /// If the object is binded to a table and that constraints are not respected, the object is not added until all constraints can apply.
            /// </remarks>
            protected override void OnListChanged(ListChangedEventArgs e)
            {
                if (e.ListChangedType == ListChangedType.ItemAdded)
                {
                    _adding = true;
                    IMessageSender<T> obj = this.Items[e.NewIndex] as BindableObject<T>;
                    if (obj != null)
                    {
                        obj.MessageSend += new EventHandler<MessageEventArgs<T>>(obj_MessageSend);
                    }
                }
            }
     
            void obj_MessageSend(object sender, MessageEventArgs<T> e)
            {
                this.OnMessageSend(e);
            }
     
            /// <summary>
           /// .ctor
           /// </summary>
            public ConnectedCollectionBase():base(new List<T>())
            {
     
            }
     
     
            /// <summary>
            /// .ctor
            /// </summary>
            /// <param name="col">The base collection that is used to fill the inner collection.</param>
            public ConnectedCollectionBase(IList<T> col)
                : base(col)
            {
     
            }
     
         }
    Il s'agit de la fameuse classe de collection.

    Toujours dans l'assembly Framework j'ai un datagrid générique... Là y a pas mal de reflexion pour binder les données je ne pense pas que le code soit utile à ce niveau là mais bon en gros ca hérite de datagrid et lors du chargement des données on a le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
     
    /// <summary>
            /// Loads the data source of the grid.
            /// </summary>
            /// <remarks>
            /// If a SourceMethod object is defined, the method is invoked. If a Binding type is defined, then
            /// the source is changed to this type. The method tries to call the constructor of the BindigType
            /// passing it the result of the previous method call as a parameter.
            /// </remarks>
            public virtual void LoadSource()
            {
                object targetSource = null;
     
                if (this.SourceMethod != null && !this.DesignMode)
                {
                    object methodCallResult = GetDataSourceFromMethod();
                    if (methodCallResult != null)
                    {
                        ConstructorInfo ctor = GetBindingTypeConstructor(methodCallResult);
     
                        if (ctor != null)
                        {
                            object[] parameters = new object[1] { methodCallResult };
                            targetSource = ctor.Invoke(parameters);
                        }
                        else
                        {
                            targetSource = methodCallResult;
                        }
                    }
                    else
                        targetSource = null;
                }
     
                this.DataSource = targetSource;
                SetMessageHandler();
            }
     
     
     
    /// <summary>
            /// If the base object of the data source implements the IrisGenerator.Common.Core.Messaging.IMessageSender`1 interface
            /// the MessageSend event will be handled in the MessageReceived method.
            /// </summary>
            protected virtual void SetMessageHandler()
            {
                if (this.DataSource == null)
                    return;
     
     
                Type interf = this.DataSource.GetType().GetInterface("IrisGenerator.Framework.Messaging.IMessageSender`1");
                if (interf != null)
                {
                    obj = this.DataSource as IMessageSender<T>;
                    if (obj != null)
                        obj.MessageSend += new EventHandler<MessageEventArgs<T>>(MessageReceived);
                }
     
            }
     
    /// <summary>
            /// Handles MessageSend events fired from the objects in the datasource
            /// </summary>
            /// <remarks>
            /// Makes a call to the MessageToMessageBox.Show method passing the message in the event argument.
            /// </remarks>
            /// <param name="sender">The object that fired the message.</param>
            /// <param name="e">The message argument that was sent.</param>
            protected virtual void MessageReceived(object sender, MessageEventArgs<T> e)
            {
                if (e != null)
                {
                    e.Message.Result = MessageToMessageBox.Show(e.Message);
                }
            }
    Voilà pour la mécanique du Framework...

    Pour la partie métier j'ai la chose suivante:

    Une méthode Delete par classe dont la structure est la suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
     
    public override bool Delete(bool fireRuleMessages)
            {
                RuleErrorCollection errors=null;
                if (this.ObjectRules.CanDelete(ref errors))
                {
                    Dal.Metatype dbo = null;
                    try
                    {
                        dbo = new Dal.Metatype();
                        BaseEventArgs<Metatype> e = new BaseEventArgs<Metatype>(this, fireRuleMessages);
                        this.OnDeleting(e);
                        if (!e.Cancel)
                        {
                            dbo.METATYPE_Delete(this.MetId);
                            return true;
                        }
                        else
                            return false;
                    }
                    catch (System.Exception ex)
                    {
                        throw;
                    }
                    finally
                    {
                        if ((dbo != null))
                        {
                            dbo.Dispose();
                        }
                    }
                }
                else
                {
                    //TODO: Traitement des erreurs...
                    return false;
                }
            }
    La méthode OnDeleting permet d'appeller une classe de règle dont la méthode est la suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
     
    void _innerObj_Deleting(object sender, BaseEventArgs<Metatype> e)
            {
                if (e.FireMessage)
                {
                    Message message = new Message("Are you sure you want to delete the metatype " + e.Argument.MetCode + "?"
                        + Environment.NewLine + "This action will delete all linked elements.", "Metatype deletion",
                        MessageButtons.YesNo, MessageIcon.Question, MessageDefaultButton.Button2);
     
                    MessageResults result = OnMessageSend(new MessageEventArgs<Metatype>(e.Argument, message));
                    if (result != MessageResults.Yes)
                    {
                        e.Cancel = true;
                        return;
                    }
                }
     
                MetatypeEquivalences.Select_METATYPE_EQUIVALENCES_By_MET_ID(e.Argument.MetId).Delete();
     
            }
    Le OnMessageChanged est géré dans la classe Metatype (là où le Delete est implémenté:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void Rules_MessageSend(object sender, IrisGenerator.Framework.Messaging.MessageEventArgs<Metatype> e)
            {
                this.OnMessageSend(e);
            }
    De là on va relancer l'évènement qui est récupéré dans la collection:

    Le souci en fait c'est que lorsque l'on arrive à ce point, MessageSend est null dans la collection alors qu'à l'entrée il référence bien ma fonction qui est dans la DataGrid... Encore plus bizarre et c'est pour cela que j'ai mis le Guid? Toto, la valeur du Guid est différente selon si l'on est au début (dans la méthode RemoveItem) ou dans le gestionnaire d'évènement obj_MessageSend ce qui laisse croire que l'on a affaire à deux instances différentes or on ne repasse jamais par le constructeur...

    Enfin si je mets tout ce beau monde dans la même assembly ca marche...

Discussions similaires

  1. Réponses: 1
    Dernier message: 15/11/2008, 19h19
  2. Réponses: 3
    Dernier message: 22/10/2007, 13h07
  3. Passage de valeurs entre fenêtres différentes
    Par Amnesiak dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 16/02/2005, 15h10
  4. [C#] Récupération de données entre 2 WinForm
    Par debug dans le forum Windows Forms
    Réponses: 2
    Dernier message: 09/09/2004, 16h19
  5. Réponses: 5
    Dernier message: 09/01/2003, 11h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo