Почему привязка завершается неудачно при привязке дочернего элемента к другому элементу при успешном выполнении родительского элемента?
Скажем, у меня есть два класса, которые могут ссылаться на третий объект пользовательского интерфейса (в этом примере кнопка).
Кроме того, родительский класс может содержать элемент дочернего класса.
Если они оба связаны с одним и тем же элементом управления, дочерний процесс не удастся, но родительский будет успешным.
Это ошибка в WPF?
Родитель:
class MyFrameworkElement : FrameworkElement
{
// A depenedency property that will contain a child element sub-element
private static readonly DependencyProperty ChildElementProperty =
DependencyProperty.Register("ChildElement",
typeof(MyChildElement),
typeof(MyFrameworkElement),
new PropertyMetadata());
[Category("ChildProperties")]
public MyChildElement ChildElement
{
set { SetValue(ChildElementProperty, value); }
get { return (MyChildElement)GetValue(ChildElementProperty); }
}
// Now, a reference to some other control, in this case we will bind a button to it!
public UIElement ButtonReferenceInParent
{
get { return (UIElement)GetValue(ButtonReferenceInParentProperty); }
set { SetValue(ButtonReferenceInParentProperty, value); }
}
// Using a DependencyProperty as the backing store for ButtonReferenceInParent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ButtonReferenceInParentProperty =
DependencyProperty.Register("ButtonReferenceInParent", typeof(UIElement), typeof(MyFrameworkElement), new UIPropertyMetadata(null));
И тогда ребенок
public class MyChildElement : FrameworkElement
{
public UIElement ButtonReferenceInChild
{
get { return (UIElement)GetValue(ButtonReferenceInChildProperty); }
set { SetValue(ButtonReferenceInChildProperty, value); }
}
public static readonly DependencyProperty ButtonReferenceInChildProperty =
DependencyProperty.Register("ButtonReferenceInChild", typeof(UIElement), typeof(MyChildElement), new UIPropertyMetadata(null));
}
ХОРОШО -
Теперь скажите, что я добавляю их в свой XAML следующим образом:
<Grid>
<my:MyFrameworkElement x:Name="ParentName" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ButtonReferenceInParent="{Binding ElementName=buttonisme}">
<my:MyFrameworkElement.ChildElement>
<my:MyChildElement x:Name="ChildName" ButtonReferenceInChild="{Binding ElementName=buttonisme}"/>
</my:MyFrameworkElement.ChildElement>
</my:MyFrameworkElement>
<Button x:Name="buttonisme" Click="buttonisme_Click" />
</Grid>
Почему привязка работает на родителя, но не на ребенке, когда я использую ту же запись EXACT?
Вот мой тестовый код...
Console.WriteLine("Parent button reference is {0}", ParentName.ButtonReferenceInParent);
if (ChildName.ButtonReferenceInChild == null)
{
Console.WriteLine("Child button reference is null!");
}
else
{
Console.WriteLine("Child button is {0}", ChildName.ButtonReferenceInChild);
}
А вот и результат теста...
Ссылка на родительскую кнопку - System.Windows.Controls.Button.
Ссылка на дочернюю кнопку пуста!
2 ответа
Короткий ответ на длинный вопрос заключается в том, что Microsoft не ожидает, что вы извлечете уроки из FrameworkElement, не сделав небольшую работу.
Просто делая деривацию, ломает логическое дерево, которое используется при выполнении привязки по имени элемента.
Вы, вероятно, также должны собрать визуальное дерево и перегрузить части упорядочения / измерения элемента каркаса. (Мы не делаем это здесь, поскольку мы не видимы в примере.)
В этом конкретном случае нам нужно добавить любые дочерние объекты вашего объекта в логическое дерево или отключить возможность связывать дочерние элементы.
Хороший пример того, кто решил это здесь
Информация о переопределении логического дерева находится здесь
В любом случае, код, необходимый для исправления этого ПРОСТОГО примера, опирался только на логическое дерево (поскольку дочерний объект на самом деле не визуален).
Добавление этой функции и изменение свойства зависимости заставляет работать привязку.
private static readonly DependencyProperty ChildElementProperty =
DependencyProperty.Register("ChildElement",
typeof(MyChildElement),
typeof(MyFrameworkElement),
new PropertyMetadata(OnChildElementChanged));
private static void OnChildElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyFrameworkElement control = d as MyFrameworkElement;
if (e.OldValue != null)
{
control.RemoveLogicalChild(e.OldValue);
}
control.AddLogicalChild(e.NewValue);
}
Во-первых, когда вы настраиваете xaml следующим образом:
<my:MyFrameworkElement x:Name="ParentName" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ButtonReferenceInParent="{Binding ElementName=buttonisme}"/>
<my:MyChildElement x:Name="ChildName" ButtonReferenceInChild="{Binding ElementName=buttonisme}"/>
Оно работает. Я сделал это, потому что подозреваю, что визуальный поиск по дереву для поиска имени элемента, который вы используете в привязке.
Я все еще выясняю, как связывание может быть успешным в вашем вложенном сценарии. Но, может быть, это может дать вам подсказку...