Created
October 5, 2013 12:08
-
-
Save pglazkov/58a26eb2ef0126f3625c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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