#silverlight #user-controls
#silverlight #пользовательские элементы управления
Вопрос:
Я создал пользовательский элемент управления, который я повторно использую для разных целей. Я определил свойство зависимости, которое содержит UIElement, которое я представляю как содержимое одной из областей в пользовательском элементе управления.
Я заметил, что когда я использую этот элемент управления. и дайте имена элементам внутри свойства content, они всегда отображаются как null во время выполнения.
MyContainer.xaml:
<UserControl x:Class="BSSApp.UI.Tests.MyContainer" x:Name="userControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Border x:Name="LayoutRoot" Background="Green" CornerRadius="20" BorderBrush="#005500" BorderThickness="10">
<ContentPresenter Content="{Binding ElementName=userControl, Path=MyContent}" Margin="20"/>
</Border>
</UserControl>
MyContainer.xaml.cs
namespace BSSApp.UI.Tests
{
public partial class MyContainer : UserControl
{
public static readonly DependencyProperty MyContentProperty =
DependencyProperty.Register("MyContent",
typeof(UIElement),
typeof(MyContainer),
new PropertyMetadata(new Grid()));
public UIElement MyContent
{
get
{
return (UIElement)GetValue(MyContentProperty);
}
set
{
SetValue(MyContentProperty, value);
}
}
public MyContainer()
{
InitializeComponent();
}
}
}
И класс using:
UserControlContentBug.xaml:
<UserControl x:Class="BSSApp.UI.Tests.UserControlContentBug"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:t="clr-namespace:BSSApp.UI.Tests"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<t:MyContainer>
<t:MyContainer.MyContent>
<Button Name="btnWithName" Click="btnWithName_Click">Click Me</Button>
</t:MyContainer.MyContent>
</t:MyContainer>
</Grid>
</UserControl>
и код, лежащий в основе:
UserControlContentBug.xaml.cs
namespace BSSApp.UI.Tests
{
public partial class UserControlContentBug : UserControl
{
public UserControlContentBug()
{
InitializeComponent();
}
private void btnWithName_Click(object sender, RoutedEventArgs e)
{
// this throws an exception
btnWithName.Tag=2;
}
}
}
Итак, есть объявление кнопки с именем «btnWithName». переменная действительно объявлена в исходном коде, но она содержит null… Это происходит только тогда, когда кнопка объявлена внутри свойства другого пользовательского элемента управления.
Кто-нибудь знает, как это решить?
Спасибо
Ответ №1:
Я только что сам столкнулся с этой проблемой. Сгенерированный частичный класс (например, obj UserControlContentBug.xaml.g.cs), который определяет доступные для кода именованные элементы в вашем XAML, использует FrameworkElement.FindName() для выполнения этих назначений.
Согласно MSDN:
API времени выполнения, такой как FindName, работает с деревом объектов. Эти объекты загружаются в область содержимого и механизм выполнения CLR всего подключаемого модуля Silverlight. Когда часть дерева объектов создается из шаблонов или загруженного во время выполнения XAML, область имен XAML обычно не является смежной со всем этим деревом объектов. Результатом является то, что в дереве объектов может быть именованный объект, который данный вызов FindName не может найти.
Поскольку MyContainer устанавливает свою собственную границу области имен как UserControl, вызов FindName() из UserControlContentBug не будет исследовать ту часть дерева объектов (где определено btnWithName).
Вероятно, есть несколько разных способов обойти это, но самый простой, который работает для меня, — это:
-
Присвойте MyContainer имя (
x:Name="myContainer"
). -
Удалите имя из кнопки (btnWithName), чтобы лишняя переменная с тем же именем, всегда имеющая значение null, не была зарезервирована в сгенерированном коде C #.
-
Создайте ссылку на кнопку в codebehind.
Вот так:
namespace BSSApp.UI.Tests
{
public partial class UserControlContentBug : UserControl
{
private Button btnWithName;
public UserControlContentBug()
{
Loaded = UserControlContentBugLoaded;
InitializeComponent();
}
private void UserControlContentBugLoaded(object sender, System.Windows.RoutedEventArgs e)
{
btnWithName = myContainer.MyContent as Button;
}
private void btnWithName_Click(object sender, RoutedEventArgs e)
{
// this throws an exception, not so much
btnWithName.Tag=2;
}
}
}
Надеюсь, это поможет.
Ответ №2:
Попробуйте использовать x:Name вместо Name на кнопке.
Комментарии:
1. Я пробовал это как с Name, так и с x: Name — но я получаю те же результаты.