-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathEnumSource.cs
129 lines (116 loc) · 4.23 KB
/
EnumSource.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace Tonic.UI
{
/// <summary>
/// Return all enums value for a given enum type or a binding to a property with an enum Type
/// Ussage:
/// </summary>
public class EnumSource : MarkupExtension
{
private readonly Type _type;
private readonly Binding _binding;
[ThreadStatic]
static Dictionary<Type, object[]> cache = new Dictionary<Type, object[]>();
/// <summary>
/// True if friendly names should be used. If used, the EnumBinding should be used instead of the WPF binding in order to convert back from the internal representation
/// </summary>
public bool Friendly { get; set; } = true;
public EnumSource(object value)
{
if (value is Type)
{
var type = (Type)value;
if (!type.IsEnum)
throw new ArgumentException("EnumToItemsSource requires that the given type is a non-nullable Enum");
_type = type;
}
else if (value is Binding)
{
_binding = (Binding)value;
}
else if (value is string str)
{
_binding = new Binding(str)
{
Mode = BindingMode.OneWay
};
}
else
throw new ArgumentException("Value must be an Enum type, a Binding or an string");
}
static readonly DependencyProperty BindingProperty =
DependencyProperty.RegisterAttached(
"Binding",
typeof(Type),
typeof(EnumSource),
new PropertyMetadata());
// https://stackoverflow.com/questions/944087/get-value-from-datacontext-to-markupextension
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (!(serviceProvider is IProvideValueTarget pvt))
{
return null;
}
if (!(pvt.TargetObject is FrameworkElement frameworkElement))
{
return this;
}
//If the type is unknown;
if (_type == null)
{
//provider of target object and it's property
var targetProvider = (IProvideValueTarget)serviceProvider
.GetService(typeof(IProvideValueTarget));
var target = (FrameworkElement)targetProvider.TargetObject;
//Extract indirectly the property type and the enum info using the GetTypeEnumConverter:
var binding = new Binding(_binding.Path.Path)
{
Mode = BindingMode.TwoWay,
};
var conv = new GetTypeEnumConverter
{
UseDescription = Friendly
};
binding.Converter = conv;
conv.Expression = (BindingExpression)binding.ProvideValue(serviceProvider);
return conv.Expression;
}
else
{
//The type is already known, extract enum info:
if (Friendly)
return GetEnumValues(_type).Select(x => EnumValue.Create(x));
else
return GetEnumValues(_type);
}
}
/// <summary>
/// Get the Enum values for a given Enum type
/// </summary>
/// <param name="Type">Enum or nullable Enum type</param>
/// <returns></returns>
public static IEnumerable<object> GetEnumValues(Type Type)
{
//Extract nullable argument:
if (Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
Type = Type.GetGenericArguments()[0];
}
object[] result;
if (!cache.TryGetValue(Type, out result))
{
result = Enum.GetValues(Type).Cast<object>().ToArray();
cache.Add(Type, result);
}
return result;
}
}
}