locked
Why can't I bind to a dictionary as an ItemsSource on a ComboBox in a Universal App?

    Question

  • I'm getting this binding error

    Error: Cannot get 'Key' value (type 'String') from type 'System.Runtime.InteropServices.WindowsRuntime.CLRIKeyValuePairImpl`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.UInt16, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. BindingExpression: Path='Key' DataItem='System.Runtime.InteropServices.WindowsRuntime.CLRIKeyValuePairImpl`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.UInt16, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'; target element is 'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is 'Text' (type 'String').

    I set up my control to do this:

        public sealed partial class PodConfigControl : UserControl
        {
            public PodConfigControl()
            {
                this.InitializeComponent();
                bsFreqcomboBox.ItemsSource = BSFreq;
            }
    
    
            static Dictionary<String, UInt16> BSFreq = new Dictionary<String, UInt16>(3);
    
    
            static PodConfigControl()
            {
                BSFreq["868Mhz"] = 0;
                BSFreq["915Mhz"] = 1;
                BSFreq["920Mhz"] = 2;
            }
    }

    And then in my XAML, I have this fragment:

                <ComboBox x:Name="bsFreqcomboBox" SelectedIndex="{Binding RadioFrequency}" 
                          Width="100" HorizontalAlignment="Left">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Key}"></TextBlock>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
    


    Anthony Wieser | Wieser Software Ltd | www.wieser-software.com

    Wednesday, September 24, 2014 3:02 PM

Answers

All replies


  • I've come up with a solution, but still don't know why the problem exists in the first place.

    It appears to be something to do with the implementation in Windows of KeyValuePair<K,V>

    I added these classes to my code:

    	public class MyPair<K, V>
    	{
    		public K Key { get; set; }
    		public V Value { get; set; }
    	}
    
    	public class DictionaryEnumerator<K, V>
    	{
    		ObservableDictionary<K, V> dict;
    		public ObservableDictionary<K, V> Dict
    		{
    			get { return dict; }
    			set { dict = value; }
    		}
    
    		public IEnumerable<MyPair<K, V>> GetPairs()
    		{
    			if (dict == null) yield break;
    
    			foreach (var v in dict)
    			{
    				MyPair<K, V> p = new MyPair<K, V>() { Key = v.Key, Value = v.Value };
    				yield return p;
    			}
    		}
    
    		public IEnumerable<MyPair<K, V>> Collection
    		{
    			get { return GetPairs(); }
    		}
    	}

    Then I can set up my dictionary like this:

    ObservableDictionary<int, String> BSFreq = new ObservableDictionary<int, String>();
                BSFreq[0] = "868Mhz";
                BSFreq[1] = "915Mhz";
                BSFreq[2] = "920Mhz";
    
    	Frequencies = new DictionaryEnumerator<int, string>() { Dict = BSFreq }; 

    And finally, I can set the Items source like this:

              bsFreqcomboBox.ItemsSource = Frequencies.Collection;
      


    Anthony Wieser | Wieser Software Ltd | www.wieser-software.com


    Thursday, September 25, 2014 8:11 AM
  • Similarly, binding a Grid's DataContext to a Dictionary gives this unhelpful error in many cases.

    A first chance exception of type 'System.BadImageFormatException' occurred in PowerlineRealtime.Windows.exe

    Additional information: Unable to compute GUID for type 'Windows.Foundation.Collections.IObservableMap`2[System.String,PowerlineRealtime.Data.XPlatformPodSummaryData]' because the instantiation contains types that are not supported by Windows Runtime.

    Again, remapping through the Collection trick shown above causes this to work.

    I added this to my specialized dictionary class:

    		public IEnumerable<MyPair<string, V>> Collection
    		{
    			get {
    				foreach (var v in this)
    				{
    					MyPair<string, V> p = new MyPair<string, V>() { Key = v.Key, Value = v.Value };
    					yield return p;
    				}
    			 }
    		}


    Anthony Wieser | Wieser Software Ltd | www.wieser-software.com

    Thursday, September 25, 2014 8:25 AM
  • Hi Anthony Wieser,

    Take a look at a similar post: http://stackoverflow.com/questions/13330938/binding-a-dictionary-to-a-winrt-listbox

    Seems to be a known issue: https://connect.microsoft.com/VisualStudio/feedback/details/750518/targetexception-error-in-binding-to-dictionary-string-object

    As a quick walk around, you can use List<> instead, but you may lost some dictionary features.

    List<dictionaryItems> myNewDictionary = new List<dictionaryItems>();
    myNewDictionary.Add(new dictionaryItems{ Key = "key1", Value = "value1" } );
    myNewDictionary.Add(new dictionaryItems{ Key = "key2", Value = "value2" });
    
    public class dictionaryItems
    {
        public string Key { get; set; }
        public string Value { get; set; }
    }

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Thursday, September 25, 2014 9:38 AM
    Moderator