2010-08-10 22 views
5

Non sono stato in grado di trovare una soluzione pulita al seguente problema, anche se ci sono già alcune domande correlate su SO.Elemento di accesso in Silverlight DataTemplate

Se si dispone di un modello di dati che viene utilizzato più volte, ad esempio, un TreeViewItem.HeaderTemplate, come posso modificare qualcosa il modello solo per alcuni dei TreeViewItems.

Ad esempio, supponiamo che il mio TVI HeaderTemplate abbia un blocco di testo e, a seconda della stringa, desidero rendere grassetto il fontweight.

voglio fare qualcosa di simile:

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

Qualcuno ha una soluzione per questo? -> Grazie Evan

Modifica: C'è un modo per scrivere una funzione generica per ottenere un controllo basato sul suo nome anche se si trova in un modello di dati?

LayoutRoot.FindName("myTextBlock"); funzionerebbe se myTextBlock non fosse in un datatemplate. Come posso scrivere una funzione findElementInDataTemplate(string elementName, string parentName)?

La ragione per cui la risposta di Evan non è quella che sto cercando è perché sto sviluppando un controllo. Voglio che lo sviluppatore dell'applicazione che utilizza il mio controllo sia in grado di modificare qualsiasi elemento nel controllo. Se utilizzo la soluzione di Evan, ciò richiederebbe allo sviluppatore dell'applicazione di avere accesso a tutti i modelli nel controllo. Possibile, ma non ideale. Grazie!

+0

Se avete usato un DataTemplate che contiene un controllo denominato "myTextBlock" più volte e poi hanno una sorta di 'LayoutRoot.FindName (operazione "myTextBlock"), quale dei molti controlli chiamati "myTextBlock" vorresti che quell'operazione fosse restituita? – AnthonyWJones

+0

@AnthonyWJones Buon punto, modificato per includere un parametro parentName. – NickHalden

+0

@AnthonyWJones: normalmente non sono possibili due controlli con nome. se si mantiene il controllo di due lo stesso nome nel modello, il modello è considerato sbagliato. – Mahantesh

risposta

0

quale versione di silverlight è questa? E quale anno di "10 agosto alle 18:55" è questo post da?

nella versione corrente di SL4 non sembra di essere lì ..

2

Se stai utilizzando l'associazione dati, hai provato a utilizzare un convertitore di binding? In questo caso si potrebbe fare qualcosa di simile ...

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

e il convertitore sarebbe lungo le linee di ...

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

che lo rende meno doloroso per cercare di radice attraverso gli elementi a individuare un particolare.

+0

Ottima soluzione alla mia domanda. Ora facciamo finta di aver posto la domanda che volevo davvero, controlla la mia modifica. – NickHalden

1

La mia prima reazione a un tale requisito sarebbe: sei proprio sicuro di volerlo fare? Normalmente sollecito gli sviluppatori a considerare i modelli di controllo esistenti utilizzati. In questo caso sembrerebbe giustificato quello che sembri un controllo Templato.

Ovviamente questo non fornisce la flessibilità necessaria. Quello che sembra essere il "Santo Graal" dei controlli personalizzabili, il desiderio di modificare qualsiasi dettaglio minore del controllo senza dover duplicare l'intero modello del controllo. Naturalmente questo non è realmente possibile in modo dichiarativo, se fosse che temerei la sintassi e le regole semantiche che lo governerebbero.

Detto questo, ci sono sempre delle eccezioni. Quindi presenterò un'opzione possibile nonostante senta che non dovresti farlo.

Questo vecchio answer fornisce un metodo di estensione Descendents che consente di enumerare i controlli attraverso la struttura ad albero degli oggetti. Dato un esempio di un TreeViewItem si dovrebbe essere in grado di trovare il TextBlock siete dopo con: -

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

Viene visualizzato il messaggio di errore L'oggetto di dipendenza IEnumerable non contiene una definizione per TypeOf – NickHalden

+0

@JGord: Assicurarsi di aver incluso 'using System.Linq' nella parte superiore del proprio file di codice. – AnthonyWJones

+0

C'era già questo, altre possibili insidie? – NickHalden

4

Un modo che ho compiuto questo è quello di memorizzare tutti gli elementi necessari a una variabile di raccolta a livello di classe, utilizzando il Loaded evento del controllo.Prendi questo DataTemplate per esempio.

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

Poi si utilizza l'evento Loaded per caricare una sorta di raccolta per un uso successivo.

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

Naturalmente, se si sta andando ad essere carico e scarico del controllo, questo potrebbe non funzionare bene per voi.

+0

Questo funziona, la risposta di AnthonyWJones è stata utile quando l'albero visivo è già stato generato, ma anche questo funziona prima – hungryMind

0

può anche provare questo

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

dove grd = il vostro elemento root (Parent dell'elemento che si sta cercando)