WPF + IoC: «Указанный Visual уже является потомком другого Visual или корнем CompositionTarget». - PullRequest
2 голосов
/ 18 апреля 2009

[Редактировать: переосмысление архитектуры вдоль линий mvvm заставило эту проблему в значительной степени исчезнуть - спасибо @ kent ]

Использование Spring.NET + WPF.

Загрузить две кнопки WPF в конфиге:

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

и передать их в конструктор класса xaml («код позади»)

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

где конструктор класса имеет:

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

Бросает:

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

Теперь я вижу, что .GetHashCode () одинаков для обеих кнопок Spring. Так что я могу понять, что не нравится WPF.

Но я не могу сделать XamlReader.Load(new XmlNodeReader(document));, как некоторые предлагали , не теряя проводку моего события.

Есть идеи как обойти это?

[Изменить] Я готовлю события. Проводка событий не проблема, но она объясняет, почему я хочу сделать это в первую очередь. Я бы оставил это из исходного поста ради краткости:

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

1 Ответ

2 голосов
/ 18 апреля 2009

Наличие одинакового хеш-кода не означает, что экземпляры объекта одинаковы. Простой способ проверить, являются ли они на самом деле одним и тем же экземпляром, - установить точку останова в конструкторе и оценить это выражение в окне наблюдения:

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

Если true, то это один и тот же объект, и это ваша проблема.

Тем не менее, я думаю, что более вероятно, что вы создаете несколько элементов управления, каждый из которых импортирует одинаковые Button s через конфигурацию Spring.

Согласно документации Spring область действия объекта по умолчанию равна singleton. Что вам действительно нужно, так это чтобы Spring создавал новый экземпляр Button для каждого элемента управления, который в этом нуждается. Поэтому ваша конфигурация должна выглядеть примерно так:

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

И, сказав все это, я думаю, вам было бы гораздо лучше, если бы вы использовали подход MVVM. Вы могли бы сделать так, чтобы Spring предоставил экземпляры модели представления (которые могут быть совместно использованы без проблем) и сгенерировал пользовательский интерфейс для этой модели.

...