Search code examples
c#wpfbindingdictionarycode-behind

How do I bind Dictionary Value based on Key to a TextBlock in Code-Behind?


I am using the MVVM model with a dynamic field generator, where the field is pulled from the database, done this way because different types of forms require different fields (TextBox/TextBlock, ComboBox, etc.). The problem is I'm trying to retrieve a value from a dictionary, to display in a TextBlock for the form, but I'm not sure how to bind the retrieved Key so I can display the value.

Currently, I am doing the following:

 TextBlock textBlock = new TextBlock();
 textBlock.SetBinding(TextBlock.TextProperty, createFieldBinding(myPropertyName);

With the following binding method:

 private Binding createFieldBinding(string fieldName) {
      Binding binding = new Binding(fieldName);
      binding.Source = this.DataContext;
      binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
      return binding;
 }

Where I pass something through like Score, which maps to a Score property in the ViewModel, but how would I bind to a Dictionary Key to retrieve its Value?

I want to be able to bind to something like myDictionaryProperty[myDictionaryKey], if that is possible.

Example: The below generates the PlayerScore for Player with ID of 1. Where PlayerScore is a Dictionary<int, int> and PlayerID is an int.

 <TextBlock Name="textBlockA" Text="{Binding PlayerScore[1]} />

Solution

  • Using this solution provided by @Clemens, I was able to build my own DictionaryItemConverter, based on the data types for my Dictionary, and create a multi-binding method that would bind the Key and the Dictionary together.

    Converter:

     public class DictionaryItemConverter : IMultiValueConverter {
          public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
               if(values != null && values.Length >= 2) {
                    var myDict = values[0] as IDictionary;
                    if(values[1] is string) {
                         var myKey = values[1] as string;
                         if(myDict != null && myKey != null) {
                              //the automatic conversion from Uri to string doesn't work
                              //return myDict[myKey];
                              return myDict[myKey].ToString();
                         }
                    }
                    else {
                         long? myKey = values[1] as long?;
                         if(myDict != null && myKey != null) {
                              //the automatic conversion from Uri to string doesn't work
                              //return myDict[myKey];
                              return myDict[myKey].ToString();
                         }
                    }
               }
    
               return Binding.DoNothing;
          }
    
          public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) {
               throw new NotSupportedException();
          }
     }
    

    Multi-Bind Method:

     private MultiBinding createFieldMultiBinding(string fieldName) {
          // Create the multi-binding
          MultiBinding mbBinding = new MultiBinding();
          // Create the dictionary binding
          Binding bDictionary = new Binding(fieldName + "List");
          bDictionary.Source = this.DataContext;
          // Create the key binding
          Binding bKey = new Binding(fieldName);
          bKey.Source = this.DataContext;
          // Set the multi-binding converter
          mbBinding.Converter = new DictionaryItemConverter();
          // Add the bindings to the multi-binding
          mbBinding.Bindings.Add(bDictionary);
          mbBinding.Bindings.Add(bKey);
    
          return mbBinding;
     }