2011-04-14 12 views
7

He creado 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.Los controles con nombre dentro de la propiedad de contenido de UserControl siempre aparecen nulos en el tiempo de ejecución

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 usando: 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 subyacente: 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; 
     } 
    } 
    } 

Así que 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 solucionar esto?

Gracias

Respuesta

0

Intente utilizar x: Nombre en lugar del nombre del botón.

+0

Lo probé con Nombre y con x: Nombre, pero obtengo los mismos resultados. –

6

Acabo de toparme con este problema yo mismo. La clase parcial generada (por ejemplo, obj \ UserControlContentBug.xaml.g.cs) que define los elementos nombrados accesibles por código en su XAML usa FrameworkElement.FindName() para realizar esas asignaciones.

De acuerdo con MSDN:

Una API de tiempo de ejecución como FindName está trabajando 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.

Desde MyContainer establece su propio límite NameScope como un control de usuario, llamando FindName() desde UserControlContentBug no va a explorar esa parte del árbol de objetos (en el que se define btnWithName).

Probablemente hay algunas maneras diferentes de trabajar alrededor de esto, pero la más simple que funciona para mí es:

  1. Dale MyContainer un nombre (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. Cree una referencia al botón en el código subyacente.

así:

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.

Cuestiones relacionadas