Index: LocalizationResourceKeyProperty.cpp
===================================================================
--- LocalizationResourceKeyProperty.cpp	(revision 16539)
+++ LocalizationResourceKeyProperty.cpp	(working copy)
@@ -22,6 +22,69 @@
 
 
////////////////////////////////////////////////////////////////////////////////////////////////////
+static void AddResourceKey(const Type* search, HashSet<Symbol>* keys,
+    const char* key, BaseComponent* value)
+{
+    if (value == nullptr)
+    {
+        return;
+    }
+
+    Symbol keySym(key, Symbol::NullIfNotFound());
+    if (keySym.IsNull() || (!keySym.IsNull() && Reflection::GetType(keySym) != nullptr))
+    {
+        return;
+    }
+
+    // Only check if type matches if we're not searching for generic BaseComponent
+    if (search != TypeOf<BaseComponent>())
+    {
+        // Find the actual type of the resource
+        const Type* resType = value->GetClassType();
+        if (Helper::IsType<BoxedValue>(value))
+        {
+            resType = ((BoxedValue*)value)->GetValueType();
+        }
+        else
+        {
+            resType = Helper::ExtractComponentType(resType);
+        }
+        if (resType == nullptr)
+        {
+            resType = value->GetClassType();
+        }
+
+        if (resType && !search->IsAssignableFrom(resType))
+        {
+            return;
+        }
+    }
+
+    keys->Insert(keySym);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+static void ProcessResources(const ResourceDictionary* resources, const Type* searchType,
+    HashSet<Symbol>* keys)
+{
+    if (resources == nullptr)
+    {
+        return;
+    }
+
+    resources->EnumKeyValues([&searchType, &keys](const char* key, BaseComponent* value)
+    {
+        AddResourceKey(searchType, keys, key, value);
+    });
+
+    ResourceDictionaryCollection* collection = resources->GetMergedDictionaries();
+    for (int i = 0; i < collection->Count(); i++)
+    {
+        ProcessResources(collection->Get(i), searchType, keys);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
 LocalizationResourceKeyProperty::LocalizationResourceKeyProperty(BasePropertySource* src):
     Property(src), mRefreshing(false)
 {
@@ -115,56 +178,24 @@
         }
     }
 
-    // Gather all keys from the dictionary
+    // Gather all keys from this dictionary, and all merged dictionaries
     if (resources && searchType)
     {
-        // TODO: search merged dictionaries?
-        struct Params
+        HashSet<Symbol> keys;
+        ProcessResources(resources, searchType, &keys);
+        for (Symbol key : keys)
         {
-            const Type* search;
-            Collection<Boxed<String>>* keys;
-        } params = { searchType, &mKeys };
-
-        // Go through resources
-        resources->EnumKeyValues([&params](const char* key, BaseComponent* value)
-        {
-            if (value == nullptr)
+            int32_t insertIndex = 0;
+            for (; insertIndex < mKeys.Count(); insertIndex++)
             {
-                return;
-            }
-
-            // Only check if type matches if we're not searching for generic BaseComponent
-            if (params.search != TypeOf<BaseComponent>())
-            {
-                // Find the actual type of the resource
-                const Type* resType = value->GetClassType();
-                if (Helper::IsType<BoxedValue>(value))
+                if (StrCaseCompare(Boxing::Unbox<String>(mKeys.Get(insertIndex)).Str(), key.Str())
+                    > 0)
                 {
-                    resType = ((BoxedValue*)value)->GetValueType();
+                    break;
                 }
-                else
-                {
-                    resType = Helper::ExtractComponentType(resType);
-                }
-                if (resType == nullptr)
-                {
-                    resType = value->GetClassType();
-                }
-
-                if (resType && !params.search->IsAssignableFrom(resType))
-                {
-                    return;
-                }
             }
-
-            Symbol keySym(key, Symbol::NullIfNotFound());
-            if (keySym != Symbol::Null() && Reflection::GetType(keySym) != nullptr)
-            {
-                return;
-            }
-
-            params.keys->Add((Boxed<String>*)Boxing::Box<String>(key).GetPtr());
-        });
+            mKeys.Insert(insertIndex, (Boxed<String>*)Boxing::Box<String>(key.Str()).GetPtr());
+        }
     }
 }
 
@@ -193,7 +224,7 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
-const Collection<Boxed<String>>* LocalizationResourceKeyProperty::GetKeys() const
+const ObservableCollection<Boxed<String>>* LocalizationResourceKeyProperty::GetKeys() const
 {
     return &mKeys;
 }
Index: LocalizationResourceKeyProperty.h
===================================================================
--- LocalizationResourceKeyProperty.h	(revision 16539)
+++ LocalizationResourceKeyProperty.h	(working copy)
@@ -32,10 +32,10 @@
     void Refresh() override;
 
     // Get list of keys
-    const Noesis::Collection<Noesis::Boxed<Noesis::String>>* GetKeys() const;
+    const Noesis::ObservableCollection<Noesis::Boxed<Noesis::String>>* GetKeys() const;
 
 private:
-    Noesis::Collection<Noesis::Boxed<Noesis::String>> mKeys;
+    Noesis::ObservableCollection<Noesis::Boxed<Noesis::String>> mKeys;
     bool mRefreshing;
 
     NS_DECLARE_REFLECTION(LocalizationResourceKeyProperty, Property)
