views:

756

answers:

1

[Edit: Rethinking architecture along mvvm lines made this problem largely fall away - thanks @kent]

Using Spring.NET + WPF.

Load two WPF buttons in the 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>

and pass them into the constructor of a xaml class ("code behind")

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

where the class constructor has:

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);
    ...

Throws a:

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

Now, I see the .GetHashCode() is the same for both buttons coming from Spring. So I can understand what WPF doesn't like.

But I can't do a XamlReader.Load(new XmlNodeReader(document)); as some have suggested, without losing my event wiring.

Any ideas how to get around this?

[Edit] I am wiring up events. Event wiring is not a problem, but it does explain why I'd want to do this in the first place. I'd left this out of the original post for the sake of brevity:

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

Having the same hash code does not mean the object instances are the same. An easy way to check whether they are actually the same instance is to set a breakpoint in your constructor and evaluate this expression in the watch window:

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

If true, they are exactly the same object and that is your problem.

That said, I think it far more likely that you are creating multiple controls, each of which imports the same Buttons through Spring configuration.

As per the Spring documentation, the default scope for an object is singleton. What you really want is for Spring to create a new instance of the Button for each control that needs it. Therefore, your configuration should look more like this:

<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>

And having said all that, I think you'd be far better off using an MVVM approach. You could have Spring provide the view model instances (which can be shared without issue) and generate the UI off that model.

HTH, Kent

Kent Boogaart
- MVVM: Great suggestion. - Spring Singleton: doh!
Jeffrey Knight