Skip to content

Instantly share code, notes, and snippets.

@pglazkov
Created October 5, 2013 12:08
Show Gist options
  • Save pglazkov/58a26eb2ef0126f3625c to your computer and use it in GitHub Desktop.
Save pglazkov/58a26eb2ef0126f3625c to your computer and use it in GitHub Desktop.
public abstract class ResourceAccessor : MarkupExtension
{
private static readonly IDictionary<Type, Uri> UriCache = new Dictionary<Type, Uri>();
public Uri Uri
{
get
{
var result = GetUriWithCache();
return result;
}
}
public Stream Stream
{
get
{
var result = Application.GetResourceStream(Uri);
return result != null ? result.Stream : null;
}
}
private Uri GetUriWithCache()
{
Uri result;
var thisType = GetType();
lock (UriCache)
{
if (!UriCache.TryGetValue(thisType, out result))
{
result = CreateUri();
CheckResourceExists(result);
UriCache.Add(thisType, result);
}
}
return result;
}
private Uri CreateUri()
{
var uriString = FormatUri();
return new Uri(uriString, UriKind.RelativeOrAbsolute);
}
private string FormatUri()
{
var assemblyInfo = GetType().Assembly;
string assemblyName = new AssemblyName(assemblyInfo.FullName).Name;
return string.Format("{0}/{1}", FormatAssemblyPath(assemblyName), FormatAssemblyRelativePath(assemblyName));
}
private static string FormatAssemblyPath(string assemblyName)
{
#if SILVERLIGHT
return string.Format("/{0};component", assemblyName);
#else
return string.Format("pack://application:,,,/{0};component", assemblyName);
#endif
}
private string FormatAssemblyRelativePath(string assemblyName)
{
var thisType = GetType();
var typeNamespace = thisType.Namespace ?? string.Empty;
var namespaceWithoutAssemblyName = typeNamespace.Replace(assemblyName, string.Empty).TrimStart('.');
if (typeNamespace == namespaceWithoutAssemblyName)
{
// Assembly name was not found as part of the namespace name, probably because it has some suffix. Try to strip that suffix.
var assemblyNameParts = assemblyName.Split('.');
if (assemblyNameParts.Length > 1)
{
var assemblyNameWithoutSuffix = string.Join(".", assemblyNameParts.Take(assemblyNameParts.Length - 1));
namespaceWithoutAssemblyName = typeNamespace.Replace(assemblyNameWithoutSuffix, string.Empty).TrimStart('.');
}
}
var pathWithoutFile = namespaceWithoutAssemblyName.Replace('.', '/');
string[] nameParts = thisType.Name.Split(new[] { "__" }, StringSplitOptions.RemoveEmptyEntries);
var resourceNameWithoutExtension = nameParts[0];
var resourceExtension = nameParts[1];
var result = string.Format("{0}/{1}.{2}", pathWithoutFile, resourceNameWithoutExtension, resourceExtension);
return result;
}
private static void CheckResourceExists(Uri uri)
{
var resourceInfo = Application.GetResourceStream(uri);
if (resourceInfo == null)
{
throw new InvalidOperationException(string.Format("Resource is expected at \"{0}\", but it doesn't exist.", uri));
}
}
#region MarkupExtension Implementation
public override object ProvideValue(IServiceProvider serviceProvider)
{
var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
Type targetPropertyType;
#if SILVERLIGHT
var propertyInfo = provideValueTarget.TargetProperty as PropertyInfo;
#else
var propertyInfo = provideValueTarget.TargetProperty as DependencyProperty;
#endif
if (propertyInfo != null)
{
targetPropertyType = propertyInfo.PropertyType;
}
else
{
throw new NotSupportedException(string.Format("provideValueTarget.TargetProperty is NULL or an instance of unsupported type: {0}", provideValueTarget.TargetProperty));
}
object result = Uri;
if (targetPropertyType != typeof (Uri))
{
var typeConverter = GetTypeConverter(targetPropertyType);
if (typeConverter != null)
{
if (typeConverter.CanConvertFrom(typeof (Uri)))
{
result = typeConverter.ConvertFrom(Uri);
}
}
}
return result;
}
private static TypeConverter GetTypeConverter(Type type)
{
var attributes = type.GetCustomAttributes(typeof(TypeConverterAttribute), false);
if (attributes.Length != 1)
return new TypeConverter();
var converterAttribute = (TypeConverterAttribute)attributes[0];
var converterType = Type.GetType(converterAttribute.ConverterTypeName);
if (converterType == null)
return new TypeConverter();
return Activator.CreateInstance(converterType) as TypeConverter;
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment