Как вложить пользовательские элементы XAML?
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1">
<Grid>
<local:ElementType x:Name="FirstElementName">
<local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" />
</local:ElementType>
</Grid>
</Window>
и это в других файлах ...
<Grid x:Name="InternalElementName" x:Class="WpfApplication1.ElementType"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
</Grid>
и ...
public partial class ElementType : System.Windows.Controls.Grid { }
все работает нормально, кроме второй элемент.
Я получаю сообщение об ошибке:
невозможно задать значение атрибута Name ' SecondElementName 'для элемента'ElementType'. "ElementType" находится в области элемента "ElementType", у которого уже было зарегистрировано имя, когда оно было определено в другой области.
пользовательские сетки определены правильно. Код будет компилироваться и запускаться, если я достану свойство - - -
x:Name="SecondElementName"
- - - в Window1.в XAML
что вызывает эту ошибку? Как мне обойти это? Мне нужно вложить одну из этих пользовательских сеток в другую, и мне нужны имена на обеих, чтобы я мог привязать их к отдельным данным.
спасибо заранее.
3 ответов
чтобы узнать, что делать с вложенными объектами разметки, анализатор XAML, среди прочего, рассмотрит, определяет ли класс .NET свойство "content" по умолчанию для использования в качестве контейнера для таких детей. Это делается с "отличным".
в вашем случае, поскольку я предполагаю, что вы хотите, чтобы вложенные объекты входили в сетку, и поскольку дочерние элементы сетки входят в коллекцию свойств "дети", вам просто нужно сделать следующее:
[ContentProperty("Children")]
public partial class ElementType : Grid
{
// your code here...
}
Если вам нужно сделать некоторую логику при добавлении дочерних элементов в элемент управления (например, разрешить только определенные типы быть дочерними элементами элемента управления ElementType), вы можете наследовать от IAddChild и реализовать методы AddChild и AddText.
Что касается проблемы именования, кажется, что только lookless элементы управления могут иметь имена детей в области экземпляра. Таким образом, вы можете назвать детей внутри ElementType.xaml, но не именованные дочерние элементы в другой разметке, где создается экземпляр ElementType. Я думаю, что это из-за того, как они оптимизируют логическое дерево или что-то. Контроль lookless, с другой стороны, это контроль только код. Поэтому, если вы превратите свой класс в простой старый пустой подкласс Grid, он работает:
public class ElementType : Grid
{
}
Ура! Меньше кода!
Если вы хотите один в другом, вы хотите поместить внутренний в свойство Content первого:
<local:ElementType x:Name="FirstElementName">
<local:ElementType.Content>
<local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" />
</local:ElementType.Content>
</local:ElementType>
Если вы не хотите изменять UserControl, используйте прикрепленное поведение. Так что вам просто нужно это там, где XAML-компиляция не удалась! Только 1 поведение для каждого UserControl, который создает проблемы.
в XAML:
<preview:PreviewControl>
<i:Interaction.Behaviors>
<behaviors:UserControlNameBehavior Name="ICanSetNames"/>
</i:Interaction.Behaviors>
</preview:PreviewControl>
в C#:
public class UserControlNameBehavior : Behavior<UserControl>
{
public string Name { get; set; }
protected override void OnAttached()
{
this.AssociatedObject.Loaded += OnLoaded;
base.OnAttached();
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
this.AssociatedObject.Name = this.Name;
}
}