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(nameof(path));
38 if (string.IsNullOrWhiteSpace(path))
39 throw new ArgumentException("path can not be an empty string", nameof(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
105 get { return _updateSourceEventName; }
109 _updateSourceEventName = value;
113 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
114 [EditorBrowsable(EditorBrowsableState.Never)]
116 public static Binding Create<TSource>(Expression<Func<TSource, object>> propertyGetter, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null,
117 string stringFormat = null)
119 if (propertyGetter == null)
120 throw new ArgumentNullException(nameof(propertyGetter));
122 return new Binding(GetBindingPath(propertyGetter), mode, converter, converterParameter, stringFormat);
125 internal override void Apply(bool fromTarget)
127 base.Apply(fromTarget);
129 if (_expression == null)
130 _expression = new BindingExpression(this, SelfPath);
132 _expression.Apply(fromTarget);
135 internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
137 object src = _source;
138 var isApplied = IsApplied;
140 base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
142 if (src != null && isApplied && fromBindingContextChanged)
145 object bindingContext = src ?? Context ?? newContext;
146 if (_expression == null && bindingContext != null)
147 _expression = new BindingExpression(this, SelfPath);
149 _expression?.Apply(bindingContext, bindObj, targetProperty);
152 internal override BindingBase Clone()
154 return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
157 internal override object GetSourceValue(object value, Type targetPropertyType)
159 if (Converter != null)
160 value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
162 return base.GetSourceValue(value, targetPropertyType);
165 internal override object GetTargetValue(object value, Type sourcePropertyType)
167 if (Converter != null)
168 value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
170 return base.GetTargetValue(value, sourcePropertyType);
173 internal override void Unapply(bool fromBindingContextChanged = false)
175 if (Source != null && fromBindingContextChanged && IsApplied)
178 base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
180 if (_expression != null)
181 _expression.Unapply();
185 static string GetBindingPath<TSource>(Expression<Func<TSource, object>> propertyGetter)
187 Expression expr = propertyGetter.Body;
189 var unary = expr as UnaryExpression;
191 expr = unary.Operand;
193 var builder = new StringBuilder();
197 var member = expr as MemberExpression;
200 var methodCall = expr as MethodCallExpression;
201 if (methodCall != null)
203 if (methodCall.Arguments.Count == 0)
204 throw new ArgumentException("Method calls are not allowed in binding expression");
206 var arguments = new List<string>(methodCall.Arguments.Count);
207 foreach (Expression arg in methodCall.Arguments)
209 if (arg.NodeType != ExpressionType.Constant)
210 throw new ArgumentException("Only constants can be used as indexer arguments");
212 object value = ((ConstantExpression)arg).Value;
213 arguments.Add(value != null ? value.ToString() : "null");
216 Type declarerType = methodCall.Method.DeclaringType;
217 DefaultMemberAttribute defaultMember = declarerType.GetTypeInfo().GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
218 string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
220 MethodInfo getterInfo =
221 declarerType.GetProperties().Where(pi => (pi.GetMethod != null) && pi.Name == indexerName && pi.CanRead && pi.GetMethod.IsPublic && !pi.GetMethod.IsStatic).Select(pi => pi.GetMethod).FirstOrDefault();
222 if (getterInfo != null)
224 if (getterInfo == methodCall.Method)
230 foreach (string argument in arguments)
235 builder.Append(argument);
241 member = methodCall.Object as MemberExpression;
244 throw new ArgumentException("Method calls are not allowed in binding expressions");
247 throw new ArgumentException("Public indexer not found");
250 throw new ArgumentException("Invalid expression type");
253 while (member != null)
255 var property = (PropertyInfo)member.Member;
256 if (builder.Length != 0)
259 builder.Insert(0, ".");
264 builder.Insert(0, property.Name);
266 // member = member.Expression as MemberExpression ?? (member.Expression as UnaryExpression)?.Operand as MemberExpression;
267 member = member.Expression as MemberExpression ?? (member.Expression is UnaryExpression ? (member.Expression as UnaryExpression).Operand as MemberExpression : null);
270 return builder.ToString();