Esecuzione di Databinding TextBlock in Silverlight / WP7

Sto usando Silverlight su Windows Phone 7.

Voglio visualizzare la prima parte di un testo in un TextBlock in grassetto e il resto nel carattere normale. Il testo completo deve essere completato. Voglio che la parte in grassetto contenga il testo di una proprietà nel mio ViewModel e che il testo normale contenga testo da una proprietà diversa.

TextBlock è definito in un DataTemplate associato a LongListSelector.

Il mio primo tentativo è stato:

      

Questo non funziona in fase di runtime con “AG_E_RUNTIME_MANAGED_UNKNOWN_ERROR” straordinariamente inutile. Questo è un problema noto perché l’elemento Run non è un FrameworkElement e non può essere associato.

Il mio prossimo tentativo è stato quello di mettere in posizione i segnaposto e quindi aggiornarli nel codice:

   Placeholder1 Placeholder2   

Nel code-behind (sì, sono desparato!):

 private void TextBlockLoaded(object sender, RoutedEventArgs e) { var textBlock = (TextBlock)sender; var viewModel = (ViewModel)textBlock.DataContext; var prop1Run = (Run)textBlock.Inlines[0]; var prop2Run = (Run)textBlock.Inlines[1]; prop1Run.Text = viewModel.Property1; prop2Run.Text = viewModel.Property2; } 

Sembrava funzionare, ma poiché sto usando LongListSelector, sebbene gli oggetti vengano riciclati, il gestore di eventi Loaded codebehind non reinizializza le Run, quindi molto rapidamente viene visualizzato il testo sbagliato …

Ho esaminato l’utilizzo dell’evento Linked di LongListSelector (che utilizzo già per liberare le immagini che visualizzo nell’elenco), ma non riesco a vedere come posso utilizzarlo per reinizializzare le proprietà del testo di Runs.

Qualsiasi aiuto apprezzato!

Ho finalmente trovato una soluzione che funziona per me.

Come ho detto nel commento, l’ approccio di Paul Stovell non avrebbe funzionato.

Ho invece utilizzato un approccio simile per aggiungere una proprietà associata a TextBlock, associata al DataContext di TextBlock e alle proprietà associate alle esecuzioni, che indicano quali proprietà ViewModel devono essere associate a:

       

Quindi, nel mio evento modificato relativo alla proprietà TextBox Target (datacontext), aggiorno i Run e iscriviti per ricevere una notifica delle modifiche alle proprietà Target TextBox. Quando si modifica una proprietà Target TextBox, ho aggiornato di conseguenza il testo di esecuzione associato.

 public static class BindableRuns { private static readonly Dictionary Handlers = new Dictionary(); private static void TargetPropertyPropertyChanged( DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { if(!(dependencyObject is TextBlock)) return; var textBlock = (TextBlock)dependencyObject; AddHandler(e.NewValue as INotifyPropertyChanged, textBlock); RemoveHandler(e.OldValue as INotifyPropertyChanged); InitializeRuns(textBlock, e.NewValue); } private static void AddHandler(INotifyPropertyChanged dataContext, TextBlock textBlock) { if (dataContext == null) return; var propertyChangedHandler = new PropertyChangedHandler(textBlock); dataContext.PropertyChanged += propertyChangedHandler.PropertyChanged; Handlers[dataContext] = propertyChangedHandler; } private static void RemoveHandler(INotifyPropertyChanged dataContext) { if (dataContext == null || !Handlers.ContainsKey(dataContext)) return; dataContext.PropertyChanged -= Handlers[dataContext].PropertyChanged; Handlers.Remove(dataContext); } private static void InitializeRuns(TextBlock textBlock, object dataContext) { if (dataContext == null) return; var runs = from run in textBlock.Inlines.OfType() let propertyName = (string)run.GetValue(TargetProperty) where propertyName != null select new { Run = run, PropertyName = propertyName }; foreach (var run in runs) { var property = dataContext.GetType().GetProperty(run.PropertyName); run.Run.Text = (string)property.GetValue(dataContext, null); } } private class PropertyChangedHandler { private readonly TextBlock _textBlock; public PropertyChangedHandler(TextBlock textBlock) { _textBlock = textBlock; } public void PropertyChanged(object sender, PropertyChangedEventArgs propertyChangedArgs) { var propertyName = propertyChangedArgs.PropertyName; var run = _textBlock.Inlines.OfType() .Where(r => (string) r.GetValue(TargetProperty) == propertyName) .SingleOrDefault(); if(run == null) return; var property = sender.GetType().GetProperty(propertyName); run.Text = (string)property.GetValue(sender, null); } } public static object GetTarget(DependencyObject obj) { return obj.GetValue(TargetProperty); } public static void SetTarget(DependencyObject obj, object value) { obj.SetValue(TargetProperty, value); } public static readonly DependencyProperty TargetProperty = DependencyProperty.RegisterAttached("Target", typeof(object), typeof(BindableRuns), new PropertyMetadata(null, TargetPropertyPropertyChanged)); } 

Ti suggerisco di provare BindableRun . L’ho usato solo in WPF, ma non vedo perché non funzionerebbe in Silverlight.