Situación:x: Nombre no funciona si el elemento envuelto en el contenido del control de usuario (Silverlight)
Tengo un "panel de envoltura" UserControl
como esto (espacios de nombres y detalles visuales eliminado por razones de brevedad):
<UserControl ...>
<Grid x:Name="LayoutRoot" Background="White">
<ContentPresenter x:Name="integratedPanelContent" Margin="5" />
</Grid>
</UserControl>
Luego, en el código subyacente he registrado una propiedad de dependencia
public FrameworkElement PanelContent
{
get { return (FrameworkElement)GetValue(PanelContentProperty); }
set { SetValue(PanelContentProperty, value); }
}
public static readonly DependencyProperty PanelContentProperty =
DependencyProperty.Register("PanelContent", typeof(FrameworkElement), typeof(MyWrapperPanel),
new PropertyMetadata(null, OnPanelContentChanged));
private static void OnPanelContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyWrapperPanel)d).OnSetContentChanged(e);
}
protected virtual void OnSetContentChanged(DependencyPropertyChangedEventArgs e)
{
if (PanelContent != null)
integratedPanelContent.Content = PanelContent;
}
Ahora puedo envolver cualquier contenido en mi control:
<my:MyWrapperPanel x:Name="myWrap">
<my:MyWrapperPanel.PanelContent>
<TextBlock x:Name="tbxNothing" Text="Nothing" />
</my:MyWrapperPanel.PanelContent>
</my:MyWrapperPanel>
Descripción del problema:
Siempre que intente utilizar el tbxNothing referencia en código subyacente, el sistema lanza NullReferenceException
porque tbxNothing, a pesar de que exista una referencia, no apunta a la TextBlock definido en XAML, pero es null
.
posible (pero inconveniente) Solución:
hay una solución donde elimino x:Name
del TextBlock, y luego me defino explícitamente TextBlock privada llamada tbxNothing
. Luego, en el manejador de eventos OnNavigatedTo
asigno el valor de la siguiente manera:
tbxNothing = myWrap.PanelContent as TextBlock;
Esto funciona, pero no es una forma correcta de hacerlo, porque si un contenido es un StackPanel que contiene controles quería, tendría que Atraviesa el árbol para encontrar lo que necesito, lo cual es extremadamente inconveniente.
Pregunta:
¿Por qué el bloque de texto ya no es visible cuando se envolvió en un control de usuario (la manera descrita), y cómo obtenerla por su x: Nombre de código subyacente?
Definitivamente voy a intentar esto, pero no estoy seguro de una cosa. Algunos elementos del MyWrapperPanel son interactivos, por lo que anteriormente he puesto algunos controladores de eventos en el código subyacente de UserControl. Si defino los elementos a través de la plantilla, ¿cómo puedo llegar a elementos específicos de la plantilla para realizar una lógica personalizada? ¿Sería posible especificar x: Name en los elementos de la plantilla en el código del control a través de FindName() o existe una forma mejor de lograr una lógica personalizada en los elementos definidos de la plantilla? –
@kornelijepetak: Sí, puede usar 'x: Name' en la plantilla; sin embargo, desde el código dentro del control personalizado de las plantillas se accede utilizando el método protegido' GetTemplateChild'. 'FindName' ahora funcionará en el namescope del' UserControl' que contiene por qué este enfoque soluciona su problema inicial. – AnthonyWJones
, pero ¿necesito usar FindName() en la página principal o puedo acceder al Bloque de texto utilizando la referencia tbxNothing? –