a3842b1dae0de1d17687672b0272b12e1db26c55
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / Binding.cs
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Globalization;
5 using System.Linq;
6 using System.Linq.Expressions;
7 using System.Reflection;
8 using System.Text;
9 using Tizen.NUI.Internals;
10
11 namespace Tizen.NUI.Binding
12 {
13         internal sealed class Binding : BindingBase
14         {
15                 internal const string SelfPath = ".";
16                 IValueConverter _converter;
17                 object _converterParameter;
18
19                 BindingExpression _expression;
20                 string _path;
21                 object _source;
22                 string _updateSourceEventName;
23
24                 public Binding()
25                 {
26                 }
27
28                 public Binding(string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null, string stringFormat = null, object source = null)
29                 {
30                         if (path == null)
31                                 throw new ArgumentNullException("path");
32                         if (string.IsNullOrWhiteSpace(path))
33                                 throw new ArgumentException("path can not be an empty string", "path");
34
35                         Path = path;
36                         Converter = converter;
37                         ConverterParameter = converterParameter;
38                         Mode = mode;
39                         StringFormat = stringFormat;
40                         Source = source;
41                 }
42
43                 public IValueConverter Converter
44                 {
45                         get { return _converter; }
46                         set
47                         {
48                                 ThrowIfApplied();
49
50                                 _converter = value;
51                         }
52                 }
53
54                 public object ConverterParameter
55                 {
56                         get { return _converterParameter; }
57                         set
58                         {
59                                 ThrowIfApplied();
60
61                                 _converterParameter = value;
62                         }
63                 }
64
65                 public string Path
66                 {
67                         get { return _path; }
68                         set
69                         {
70                                 ThrowIfApplied();
71
72                                 _path = value;
73                                 _expression = new BindingExpression(this, !string.IsNullOrWhiteSpace(value) ? value : SelfPath);
74                         }
75                 }
76
77                 public object Source
78                 {
79                         get { return _source; }
80                         set
81                         {
82                                 ThrowIfApplied();
83                                 _source = value;
84                         }
85                 }
86
87                 [EditorBrowsable(EditorBrowsableState.Never)]
88                 public string UpdateSourceEventName {
89                         get { return _updateSourceEventName; }
90                         set {
91                                 ThrowIfApplied();
92                                 _updateSourceEventName = value;
93                         }
94                 }
95
96                 [Obsolete]
97                 public static Binding Create<TSource>(Expression<Func<TSource, object>> propertyGetter, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null,
98                                                                                           string stringFormat = null)
99                 {
100                         if (propertyGetter == null)
101                                 throw new ArgumentNullException("propertyGetter");
102
103                         string path = GetBindingPath(propertyGetter);
104                         return new Binding(path, mode, converter, converterParameter, stringFormat);
105                 }
106
107                 internal override void Apply(bool fromTarget)
108                 {
109                         base.Apply(fromTarget);
110
111                         if (_expression == null)
112                                 _expression = new BindingExpression(this, SelfPath);
113
114                         _expression.Apply(fromTarget);
115                 }
116
117                 internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
118                 {
119                         object src = _source;
120                         var isApplied = IsApplied;
121
122                         base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
123
124                         if (src != null && isApplied && fromBindingContextChanged)
125                                 return;
126
127                         object bindingContext = src ?? Context ?? newContext;
128                         if (_expression == null && bindingContext != null)
129                                 _expression = new BindingExpression(this, SelfPath);
130
131                         _expression?.Apply(bindingContext, bindObj, targetProperty);
132                 }
133
134                 internal override BindingBase Clone()
135                 {
136                         return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
137                 }
138
139                 internal override object GetSourceValue(object value, Type targetPropertyType)
140                 {
141                         if (Converter != null)
142                                 value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
143
144                         return base.GetSourceValue(value, targetPropertyType);
145                 }
146
147                 internal override object GetTargetValue(object value, Type sourcePropertyType)
148                 {
149                         if (Converter != null)
150                                 value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
151
152                         return base.GetTargetValue(value, sourcePropertyType);
153                 }
154
155                 internal override void Unapply(bool fromBindingContextChanged = false)
156                 {
157                         if (Source != null && fromBindingContextChanged && IsApplied)
158                                 return;
159                         
160                         base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
161
162                         if (_expression != null)
163                                 _expression.Unapply();
164                 }
165
166                 [Obsolete]
167                 static string GetBindingPath<TSource>(Expression<Func<TSource, object>> propertyGetter)
168                 {
169                         Expression expr = propertyGetter.Body;
170
171                         var unary = expr as UnaryExpression;
172                         if (unary != null)
173                                 expr = unary.Operand;
174
175                         var builder = new StringBuilder();
176
177                         var indexed = false;
178
179                         var member = expr as MemberExpression;
180                         if (member == null)
181                         {
182                                 var methodCall = expr as MethodCallExpression;
183                                 if (methodCall != null)
184                                 {
185                                         if (methodCall.Arguments.Count == 0)
186                                                 throw new ArgumentException("Method calls are not allowed in binding expression");
187
188                                         var arguments = new List<string>(methodCall.Arguments.Count);
189                                         foreach (Expression arg in methodCall.Arguments)
190                                         {
191                                                 if (arg.NodeType != ExpressionType.Constant)
192                                                         throw new ArgumentException("Only constants can be used as indexer arguments");
193
194                                                 object value = ((ConstantExpression)arg).Value;
195                                                 arguments.Add(value != null ? value.ToString() : "null");
196                                         }
197
198                                         Type declarerType = methodCall.Method.DeclaringType;
199                                         DefaultMemberAttribute defaultMember = declarerType.GetTypeInfo().GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
200                                         string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
201
202                                         MethodInfo getterInfo =
203                                                 declarerType.GetProperties().Where(pi => pi.Name == indexerName && pi.CanRead && pi.GetMethod.IsPublic && !pi.GetMethod.IsStatic).Select(pi => pi.GetMethod).FirstOrDefault();
204                                         if (getterInfo != null)
205                                         {
206                                                 if (getterInfo == methodCall.Method)
207                                                 {
208                                                         indexed = true;
209                                                         builder.Append("[");
210
211                                                         var first = true;
212                                                         foreach (string argument in arguments)
213                                                         {
214                                                                 if (!first)
215                                                                         builder.Append(",");
216
217                                                                 builder.Append(argument);
218                                                                 first = false;
219                                                         }
220
221                                                         builder.Append("]");
222
223                                                         member = methodCall.Object as MemberExpression;
224                                                 }
225                                                 else
226                                                         throw new ArgumentException("Method calls are not allowed in binding expressions");
227                                         }
228                                         else
229                                                 throw new ArgumentException("Public indexer not found");
230                                 }
231                                 else
232                                         throw new ArgumentException("Invalid expression type");
233                         }
234
235                         while (member != null)
236                         {
237                                 var property = (PropertyInfo)member.Member;
238                                 if (builder.Length != 0)
239                                 {
240                                         if (!indexed)
241                                                 builder.Insert(0, ".");
242                                         else
243                                                 indexed = false;
244                                 }
245
246                                 builder.Insert(0, property.Name);
247
248                                 //                              member = member.Expression as MemberExpression ?? (member.Expression as UnaryExpression)?.Operand as MemberExpression;
249                                 member = member.Expression as MemberExpression ?? (member.Expression is UnaryExpression ? (member.Expression as UnaryExpression).Operand as MemberExpression : null);
250                         }
251
252                         return builder.ToString();
253                 }
254         }
255 }