One way I can think of is to filter the content of the resource manager.
Here is the implementation of the above idea encapsulated in a custom extension method:
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Resources;
namespace System.Windows.Forms
{
public static partial class Extensions
{
public static void ApplyResources(this Control target, Func<KeyValuePair<string, object>, bool> filter, CultureInfo culture = null)
{
ApplyResources(new FilteringComponentResourceManager(target.GetType(), filter), target, "$this", culture);
}
static void ApplyResources(FilteringComponentResourceManager resourceManager, Control target, string name, CultureInfo culture = null)
{
// Have the resource manager apply the resources to the given target
resourceManager.ApplyResources(target, name, culture);
// Iterate through the collection of children and recursively apply resources
foreach (Control child in target.Controls)
{
if (child is UserControl)
ApplyResources(child, resourceManager.Filter, culture);
else
ApplyResources(resourceManager, child, child.Name, culture);
}
}
class FilteringComponentResourceManager : ComponentResourceManager
{
ComponentResourceManager source;
Func<KeyValuePair<string, object>, bool> filter;
public FilteringComponentResourceManager(Type type, Func<KeyValuePair<string, object>, bool> filter)
{
this.source = new ComponentResourceManager(type);
this.filter = filter;
}
public Func<KeyValuePair<string, object>, bool> Filter { get { return filter; } }
protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
{
var sourceSet = source.GetResourceSet(culture, createIfNotExists, tryParents);
return sourceSet != null ? new FilteredResourceSet(sourceSet, filter) : null;
}
class FilteredResourceSet : ResourceSet
{
public FilteredResourceSet(ResourceSet source, Func<KeyValuePair<string, object>, bool> filter)
{
foreach (DictionaryEntry entry in source)
{
if (filter(new KeyValuePair<string, object>((string)entry.Key, entry.Value)))
Table.Add(entry.Key, entry.Value);
}
}
}
}
}
}
Filtering is achieved with two custom classes - one derived from ComponentResourceManager and one derived from ResourceSet. The first class overrides the InternalGetResourceSet in order to create and return an instance of the second type, which performs the actual filtering.
Sample usages:
To apply only properties named Text:
this.ApplyResources(entry => entry.Key.EndsWith(".Text"));
To apply only properties of type string:
this.ApplyResources(entry => entry.Value is string);