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);