Skip to content

Instantly share code, notes, and snippets.

@robertjf
Last active October 4, 2016 19:29
Show Gist options
  • Select an option

  • Save robertjf/78a97240e4304b8e5bcc to your computer and use it in GitHub Desktop.

Select an option

Save robertjf/78a97240e4304b8e5bcc to your computer and use it in GitHub Desktop.
NuPicker TypeConverter for Ditto - this allows Ditto to convert from a nuPickers.Picker object to the target type
using nuPickers;
using Our.Umbraco.Ditto;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Web;
using Umbraco.Core.Models;
using Umbraco.Web;
namespace Extensions.TypeConverters
{
/// <summary>
/// Converts a NuPicker value into a Ditto object or string.
/// </summary>
/// <remarks>
/// This can be used with a single type (e.g. string) or IEnumerable<>.
///
/// If the target type is string, then this will return the Name(s) of each picked content node.
/// Otherwise it will use Ditto to try and convert the IPublishedContent item(s) to the target type.
///
/// Handles single objects as well as IEnumerable<>.
///
/// E.G.:
///
/// [TypeConverter(typeof(DittoNuPickerTypeConverter))]
/// public IEnumerable<MyPoco> MyProperty { get; set; }
///
/// // Returns a single MyPoco
/// [TypeConverter(typeof(DittoNuPickerTypeConverter))]
/// public MyPoco MyProperty { get; set; }
///
/// // Returns a list of strings based on the Name of each item.
/// [TypeConverter(typeof(DittoNuPickerTypeConverter))]
/// public IEnumerable<string> MyProperty { get; set; }
///
/// // Returns the Name of the first item.
/// [TypeConverter(typeof(DittoNuPickerTypeConverter))]
/// public string MyProperty { get; set; }
/// </remarks>
public class DittoNuPickerTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return typeof(Picker).IsAssignableFrom(sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
MethodInfo dittoAs = typeof(Our.Umbraco.Ditto.PublishedContentExtensions)
.GetMethod(
"As",
BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly,
null,
new Type[] {
typeof(IPublishedContent),
typeof(Action<ConvertingTypeEventArgs>),
typeof(Action<ConvertedTypeEventArgs>),
typeof(CultureInfo) },
null);
// get type of objects to be returned in the collection
Type outputItemType = context.PropertyDescriptor.PropertyType;
bool isList = (outputItemType.IsGenericType && outputItemType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
bool isString = isList ?
typeof(string).IsAssignableFrom(outputItemType.GetGenericArguments()[0]) :
outputItemType.IsAssignableFrom(typeof(string));
// create a list for the output collection
// Get the list as IPublishedContent.
var picker = value as Picker;
var items = picker.AsPublishedContent();
if (isList)
{
object outputList = Activator.CreateInstance(typeof(List<>).MakeGenericType(outputItemType.GetGenericArguments()[0]));
foreach (IPublishedContent inputItem in items)
{
if (isString)
{
((IList)outputList).Add(inputItem.Name);
}
else {
((IList)outputList).Add(
dittoAs
.MakeGenericMethod(new[] { outputItemType })
.Invoke(null, new[] { inputItem, null, null, null })
);
}
}
return outputList;
}
else
{
if (isString)
{
return items.Any() ? items.FirstOrDefault().Name : null;
}
else
{
return dittoAs
.MakeGenericMethod(new[] { outputItemType })
.Invoke(null, new[] { items.FirstOrDefault(), null, null, null });
}
}
}
}
}
@naepalm

naepalm commented Oct 4, 2016

Copy link
Copy Markdown

Hey, @JimBobSquarePants, does your technique still work? Or is there a better way now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment