2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Globalization;
6 using System.Linq.Expressions;
7 using System.Reflection;
9 using Tizen.NUI.Binding.Internals;
11 namespace Tizen.NUI.Binding
13 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
14 [EditorBrowsable(EditorBrowsableState.Never)]
15 public sealed class Binding : BindingBase
17 internal const string SelfPath = ".";
18 IValueConverter _converter;
19 object _converterParameter;
21 BindingExpression _expression;
24 string _updateSourceEventName;
26 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
27 [EditorBrowsable(EditorBrowsableState.Never)]
32 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
33 [EditorBrowsable(EditorBrowsableState.Never)]
34 public Binding(string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null, string stringFormat = null, object source = null)
37 throw new ArgumentNullException("path");
38 if (string.IsNullOrWhiteSpace(path))
39 throw new ArgumentException("path can not be an empty string", "path");
42 Converter = converter;
43 ConverterParameter = converterParameter;
45 StringFormat = stringFormat;
49 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
50 [EditorBrowsable(EditorBrowsableState.Never)]
51 public IValueConverter Converter
53 get { return _converter; }
62 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
63 [EditorBrowsable(EditorBrowsableState.Never)]
64 public object ConverterParameter
66 get { return _converterParameter; }
71 _converterParameter = value;
75 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
76 [EditorBrowsable(EditorBrowsableState.Never)]
85 _expression = new BindingExpression(this, !string.IsNullOrWhiteSpace(value) ? value : SelfPath);
89 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
90 [EditorBrowsable(EditorBrowsableState.Never)]
93 get { return _source; }
101 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
102 [EditorBrowsable(EditorBrowsableState.Never)]
103 public string UpdateSourceEventName {
104 get { return _updateSourceEventName; }
107 _updateSourceEventName = value;
111 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
112 [EditorBrowsable(EditorBrowsableState.Never)]
114 public static Binding Create<TSource>(Expression<Func<TSource, object>> propertyGetter, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null,
115 string stringFormat = null)
117 if (propertyGetter == null)
118 throw new ArgumentNullException("propertyGetter");
120 return new Binding(GetBindingPath(propertyGetter), mode, converter, converterParameter, stringFormat);
123 internal override void Apply(bool fromTarget)
125 base.Apply(fromTarget);
127 if (_expression == null)
128 _expression = new BindingExpression(this, SelfPath);
130 _expression.Apply(fromTarget);
133 internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
135 object src = _source;
136 var isApplied = IsApplied;
138 base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
140 if (src != null && isApplied && fromBindingContextChanged)
143 object bindingContext = src ?? Context ?? newContext;
144 if (_expression == null && bindingContext != null)
145 _expression = new BindingExpression(this, SelfPath);
147 _expression?.Apply(bindingContext, bindObj, targetProperty);
150 internal override BindingBase Clone()
152 return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
155 internal override object GetSourceValue(object value, Type targetPropertyType)
157 if (Converter != null)
158 value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
160 return base.GetSourceValue(value, targetPropertyType);
163 internal override object GetTargetValue(object value, Type sourcePropertyType)
165 if (Converter != null)
166 value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
168 return base.GetTargetValue(value, sourcePropertyType);
171 internal override void Unapply(bool fromBindingContextChanged = false)
173 if (Source != null && fromBindingContextChanged && IsApplied)
176 base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
178 if (_expression != null)
179 _expression.Unapply();
183 static string GetBindingPath<TSource>(Expression<Func<TSource, object>> propertyGetter)
185 Expression expr = propertyGetter.Body;
187 var unary = expr as UnaryExpression;
189 expr = unary.Operand;
191 var builder = new StringBuilder();
195 var member = expr as MemberExpression;
198 var methodCall = expr as MethodCallExpression;
199 if (methodCall != null)
201 if (methodCall.Arguments.Count == 0)
202 throw new ArgumentException("Method calls are not allowed in binding expression");
204 var arguments = new List<string>(methodCall.Arguments.Count);
205 foreach (Expression arg in methodCall.Arguments)
207 if (arg.NodeType != ExpressionType.Constant)
208 throw new ArgumentException("Only constants can be used as indexer arguments");
210 object value = ((ConstantExpression)arg).Value;
211 arguments.Add(value != null ? value.ToString() : "null");
214 Type declarerType = methodCall.Method.DeclaringType;
215 DefaultMemberAttribute defaultMember = declarerType.GetTypeInfo().GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
216 string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
218 MethodInfo getterInfo =
219 declarerType.GetProperties().Where(pi => (pi.GetMethod != null) && pi.Name == indexerName && pi.CanRead && pi.GetMethod.IsPublic && !pi.GetMethod.IsStatic).Select(pi => pi.GetMethod).FirstOrDefault();
220 if (getterInfo != null)
222 if (getterInfo == methodCall.Method)
228 foreach (string argument in arguments)
233 builder.Append(argument);
239 member = methodCall.Object as MemberExpression;
242 throw new ArgumentException("Method calls are not allowed in binding expressions");
245 throw new ArgumentException("Public indexer not found");
248 throw new ArgumentException("Invalid expression type");
251 while (member != null)
253 var property = (PropertyInfo)member.Member;
254 if (builder.Length != 0)
257 builder.Insert(0, ".");
262 builder.Insert(0, property.Name);
264 // member = member.Expression as MemberExpression ?? (member.Expression as UnaryExpression)?.Operand as MemberExpression;
265 member = member.Expression as MemberExpression ?? (member.Expression is UnaryExpression ? (member.Expression as UnaryExpression).Operand as MemberExpression : null);
268 return builder.ToString();