2009-04-18 5 views
2

[Edit: Repenser l'architecture le long des lignes MVVM fait ce problème tombe en grande partie loin - grâce @kent]WPF + IoC: "Le visuel spécifié est déjà un enfant d'un autre Visual ou la racine d'un CompositionTarget."

En utilisant Spring.NET + WPF.

charge deux boutons WPF dans la config:

<object name="Button1" type="System.Windows.Controls.Button, PresentationFramework" > 
    <property name="Name" value="Next" /> 
    <property name="Width" value="200"/> 
    <property name="Content" value="Next"/> 
</object> 
<object name="Button2" type="System.Windows.Controls.Button, PresentationFramework" > 
    <property name="Name" value="Back" /> 
    <property name="Width" value="200"/> 
    <property name="Content" value="Back"/> 
</object> 

et les passer dans le constructeur d'une classe de XAML ("code derrière")

<object name="MyNewScreen" type="MyControls.MyUserControl> 
    <constructor-arg name="buttons"> 
<list> 
    <ref object="Button1"/> 
    <ref object="Button2"/> 
</list> 
</object> 

où le constructeur de la classe a:

public DataGridControl(ArrayList buttons) 
{ 
    //(yes this should be a List<Button> but I can't make spring happy with that) 
    foreach(var b in buttons) this.stackPanel.Children.Add(b); 
    ... 

Lève une:

Specified Visual is already a child of another Visual or the root of a CompositionTarget.

Maintenant, je vois le .GetHashCode() est le même pour les deux boutons provenant de Spring. Donc je peux comprendre ce que WPF n'aime pas.

Mais je ne peux pas faire un XamlReader.Load(new XmlNodeReader(document)); comme some have suggested, sans perdre mon câblage d'événement.

Toute idée comment contourner cela? [Edit] Je suis en train de câbler des événements. Le câblage d'événement n'est pas un problème, mais il explique pourquoi je voudrais le faire en premier lieu. Je l'avais laissé sur ce poste d'origine pour des raisons de concision:

<object id="eventListener2" type="MyEventListener"> 
<listener event="Click" method="b_Click"> 
<ref object="Button2" /> 
</listener> 
</object> 

Répondre

2

ayant le même code de hachage ne signifie pas que les instances d'objets sont les mêmes. Un moyen facile de vérifier si elles sont en fait la même instance est de définir un point d'arrêt dans votre constructeur et évaluer cette expression dans la fenêtre de la montre:

object.ReferenceEquals(buttons[0], buttons[1]) 

Si true, ils sont exactement le même objet et qui est votre problème . Cela dit, je pense qu'il est beaucoup plus probable que vous créez plusieurs contrôles, dont chacun importe les mêmes Button via la configuration Spring.

Selon le Spring documentation, la portée par défaut d'un objet est singleton. Ce que vous voulez vraiment, c'est que Spring crée une nouvelle instance du bouton pour chaque contrôle qui en a besoin. Par conséquent, votre configuration devrait ressembler à ceci:

<object name="Button1" type="System.Windows.Controls.Button, PresentationFramework" singleton="false"> 
    <property name="Name" value="Next" /> 
    <property name="Width" value="200"/> 
    <property name="Content" value="Next"/> 
</object> 

Et après avoir dit tout cela, je pense que vous seriez bien mieux en utilisant une approche MVVM. Spring peut fournir les instances de modèle de vue (qui peuvent être partagées sans problème) et générer l'interface utilisateur de ce modèle.

+0

- MVVM: Excellente suggestion. - Printemps Singleton: Doh! –