2010-08-10 12 views
5

No he podido encontrar una solución limpia al siguiente problema aunque ya hay algunas preguntas relacionadas en SO.Elemento de acceso dentro de Silverlight DataTemplate

Si tengo una plantilla de datos que se usa varias veces, por ejemplo, TreeViewItem.HeaderTemplate, ¿cómo puedo cambiar algo la plantilla solo para algunos TreeViewItems?

Por ejemplo, digamos que mi TVI HeaderTemplate tiene un bloque de texto y, dependiendo de la cadena, quiero que el fontweight sea negrita.

quiero hacer algo como esto:

((TextBlock)myTreeView.Items.ElementAt(0).FindName("myTextBlock")).FontWeight = FontWeights.Bold; 

¿Alguien tiene una solución para esto? -> Gracias Evan

Edit: ¿Hay alguna manera de escribir una función genérica para obtener un control basado en su nombre incluso si está en una plantilla de datos?

LayoutRoot.FindName("myTextBlock"); funcionaría si myTextBlock no estuviera en una plantilla de datos. ¿Cómo puedo escribir una función findElementInDataTemplate(string elementName, string parentName)?

La razón por la que la respuesta de Evan no es lo que estoy buscando es porque estoy desarrollando un control. Quiero que el desarrollador de la aplicación que usa mi control pueda cambiar cualquier elemento en el control. Si uso la solución de Evan, eso requeriría que el desarrollador de la aplicación tenga acceso a todas las plantillas en el control. Posible, pero no ideal. ¡Gracias!

+0

Si ha utilizado un DataTemplate que contiene un control llamado "myTextBlock" varias veces y luego tienen algún tipo de 'LayoutRoot.FindName ("myTextBlock") 'operación, ¿cuál de los muchos controles llamados" myTextBlock "le gustaría que la operación vuelva? – AnthonyWJones

+0

@AnthonyWJones Buen punto, editado para incluir un parámetro parentName. – NickHalden

+0

@AnthonyWJones: Normalmente, dos controles con nombre no son posibles. si mantiene dos controles de mismo nombre en la plantilla, entonces la plantilla se considera incorrecta. – Mahantesh

Respuesta

0

¿qué versión de silverlight es esto? ¿Y en qué año de "10 de agosto a las 18:55" es esta publicación?

en la versión actual de SL4 no parece estar allí ..

2

Si está utilizando el enlace de datos, ¿ha intentado utilizar un convertidor de enlace? En este caso se hace algo como ...

FontWeight={Binding Path=TextProperty, Converter={StaticResource BoldConverter}} 

y el convertidor sería lo largo de las líneas de ...

string myTestString = (string)value; 
if (myTestString.Contains("Bob")) 
    return FontWeights.Bold; 
return FontWeights.Normal; 

que hace que sea menos dolorosa para tratar de raíz a través de los elementos a localizar uno en particular.

+0

Gran solución a mi pregunta. Ahora imaginemos que hice la pregunta que realmente quise decir, revisa mi edición. – NickHalden

1

Mi primera reacción a tal requisito sería: ¿estás realmente seguro de que quieres estar haciendo eso? Normalmente, les pido a los desarrolladores que observen los patrones de control existentes que se utilizan. En este caso, lo que parezca un control de Templado parece justificado.

Por supuesto, esto no proporciona la flexibilidad que busca. Lo que parece que buscas es el "santo grial" de los controles personalizables, el deseo de modificar cualquier detalle menor sobre el control sin tener que duplicar toda la plantilla del control. Por supuesto, esto no es realmente posible en forma declarativa, si lo fuera, temería la sintaxis y las reglas semánticas que lo regirían.

Habiendo dicho que siempre hay excepciones. Entonces, presentaré una posible opción a pesar de sentir que no deberías estar haciendo esto.

Este antiguo answer proporciona un método de extensión Descendents que le permite enumerar los controles en el árbol de objetos. Dada una instancia de un TreeViewItem usted debería ser capaz de encontrar el TextBlock que está después con: -

TextBlock tb = treeViewItem.Descendents() 
       .OfType<TextBlock>() 
       .Where(t => t.Name == "myTextBlock") 
       .FirstOrDefault(); 
+0

Aparece el mensaje de error El objeto de dependencia IEnumerable no contiene una definición para TypeOf – NickHalden

+0

@JGord: asegúrese de haber incluido 'using System.Linq' en la parte superior de su archivo de código. – AnthonyWJones

+0

¿Ya tenía eso allí, otras posibles trampas? – NickHalden

4

Una forma he logrado esto es almacenar todos los elementos necesarios en una variable de recogida a nivel de clase mediante el uso de la Loaded evento del control.Tome esta DataTemplate por ejemplo.

<DataTemplate> 
    ... 
    <TextBlock Loaded="TemplateTextBlock_Loaded" /> 
</DataTemplate> 

A continuación, se utiliza el evento Loaded para cargar algún tipo de recogida para su uso posterior.

private List<TextBlock> templateTextBlocks = new List<TextBlock>(); 

private void TemplateTextBlock_Loaded(object sender, RoutedEventArgs e) 
{ 
    TextBlock tb = sender as TextBlock; 
    if (!this.templateTextBlocks.Contains(tb)) this.templateTextBlocks.Add(tb); 
} 

Por supuesto, si va a cargar y descargar el control, puede que esto no funcione bien para usted.

+0

Esto me funciona, la respuesta de AnthonyWJones fue útil cuando el árbol visual ya se había generado, pero este funciona antes de eso también – hungryMind

0

también puede probar este

TextBlock txtBlk = grd.FindName ("txtBlkName") como TextBlock;

donde GRD = el elemento raíz (padre del elemento que busca)

Cuestiones relacionadas