silverlight user-controls

silverlight - Los controles con nombre dentro de la propiedad de contenido de UserControl siempre aparecen nulos en el tiempo de ejecuciĆ³n



user-controls (2)

Creé un control de usuario que reutilizo para diferentes propósitos. Definí una Propiedad de dependencia que contiene un UIElement, que presento como el contenido de una de las áreas en el control del usuario.

Me di cuenta de que cuando uso este control. y dar nombres a los elementos dentro de la propiedad de contenido, siempre aparecen como nulos en tiempo de ejecución.

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(); } } }

Y la clase de uso: 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>

y el código detrás: 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; } } }

Entonces hay una declaración de un botón, llamado "btnWithName". la variable se declara efectivamente en el código subyacente, pero contiene nulo ... Solo ocurre cuando el botón se declara dentro de una propiedad de otro control de usuario.

¿Alguien sabe cómo resolver esto?

Gracias


Intente usar x: nombre en lugar de nombre en el botón.


Me encontré con este problema yo mismo. La clase parcial generada (por ejemplo, obj / UserControlContentBug.xaml.g.cs) que define los elementos nombrados accesibles al código en su XAML utiliza FrameworkElement.FindName () para realizar esas asignaciones.

De acuerdo con MSDN:

Una API en tiempo de ejecución como FindName funciona contra un árbol de objetos. Estos objetos se cargan en el área de contenido y el motor de tiempo de ejecución de CLR del complemento Silverlight en general. Cuando se crea una parte del árbol de objetos a partir de plantillas o XAML cargado en tiempo de ejecución, un namescope XAML generalmente no es contiguo con la totalidad de ese árbol de objetos. El resultado es que puede haber un objeto con nombre en el árbol de objetos que una llamada FindName determinada no puede encontrar.

Como MyContainer establece su propio límite de namescope como UserControl, llamar a FindName () desde UserControlContentBug no explorará esa parte del árbol de objetos (donde se define btnWithName).

Probablemente hay algunas formas diferentes de solucionar este problema, pero la más simple que funciona para mí es:

  1. Dale un nombre a MyContainer ( x:Name="myContainer" ).

  2. Elimine el nombre del Botón (btnWithName) para que la variable superflua, siempre nula del mismo nombre no esté reservada en el código C # generado.

  3. Crea una referencia al Botón en el código subyacente.

Al igual que:

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

Espero que esto ayude.