bbbd9d918f325723c664319ea14734f651d8241f
[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.Binding.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                         return new Binding(GetBindingPath(propertyGetter), mode, converter, converterParameter, stringFormat);
104                 }
105
106         internal override void Apply(bool fromTarget)
107         {
108             base.Apply(fromTarget);
109
110             if (_expression == null)
111                 _expression = new BindingExpression(this, SelfPath);
112
113             _expression.Apply(fromTarget);
114         }
115
116         internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
117         {
118             object src = _source;
119             var isApplied = IsApplied;
120
121             base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
122
123             if (src != null && isApplied && fromBindingContextChanged)
124                 return;
125
126             object bindingContext = src ?? Context ?? newContext;
127             if (_expression == null && bindingContext != null)
128                 _expression = new BindingExpression(this, SelfPath);
129
130             _expression?.Apply(bindingContext, bindObj, targetProperty);
131         }
132
133         internal override BindingBase Clone()
134         {
135             return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
136         }
137
138         internal override object GetSourceValue(object value, Type targetPropertyType)
139         {
140             if (Converter != null)
141                 value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
142
143             return base.GetSourceValue(value, targetPropertyType);
144         }
145
146         internal override object GetTargetValue(object value, Type sourcePropertyType)
147         {
148             if (Converter != null)
149                 value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
150
151             return base.GetTargetValue(value, sourcePropertyType);
152         }
153
154         internal override void Unapply(bool fromBindingContextChanged = false)
155         {
156             if (Source != null && fromBindingContextChanged && IsApplied)
157                 return;
158             
159             base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
160
161             if (_expression != null)
162                 _expression.Unapply();
163         }
164
165         [Obsolete]
166         static string GetBindingPath<TSource>(Expression<Func<TSource, object>> propertyGetter)
167         {
168             Expression expr = propertyGetter.Body;
169
170             var unary = expr as UnaryExpression;
171             if (unary != null)
172                 expr = unary.Operand;
173
174             var builder = new StringBuilder();
175
176             var indexed = false;
177
178             var member = expr as MemberExpression;
179             if (member == null)
180             {
181                 var methodCall = expr as MethodCallExpression;
182                 if (methodCall != null)
183                 {
184                     if (methodCall.Arguments.Count == 0)
185                         throw new ArgumentException("Method calls are not allowed in binding expression");
186
187                     var arguments = new List<string>(methodCall.Arguments.Count);
188                     foreach (Expression arg in methodCall.Arguments)
189                     {
190                         if (arg.NodeType != ExpressionType.Constant)
191                             throw new ArgumentException("Only constants can be used as indexer arguments");
192
193                         object value = ((ConstantExpression)arg).Value;
194                         arguments.Add(value != null ? value.ToString() : "null");
195                     }
196
197                     Type declarerType = methodCall.Method.DeclaringType;
198                     DefaultMemberAttribute defaultMember = declarerType.GetTypeInfo().GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
199                     string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
200
201                     MethodInfo getterInfo =
202                         declarerType.GetProperties().Where(pi => (pi.GetMethod != null) && pi.Name == indexerName && pi.CanRead && pi.GetMethod.IsPublic && !pi.GetMethod.IsStatic).Select(pi => pi.GetMethod).FirstOrDefault();
203                     if (getterInfo != null)
204                     {
205                         if (getterInfo == methodCall.Method)
206                         {
207                             indexed = true;
208                             builder.Append("[");
209
210                             var first = true;
211                             foreach (string argument in arguments)
212                             {
213                                 if (!first)
214                                     builder.Append(",");
215
216                                 builder.Append(argument);
217                                 first = false;
218                             }
219
220                             builder.Append("]");
221
222                             member = methodCall.Object as MemberExpression;
223                         }
224                         else
225                             throw new ArgumentException("Method calls are not allowed in binding expressions");
226                     }
227                     else
228                         throw new ArgumentException("Public indexer not found");
229                 }
230                 else
231                     throw new ArgumentException("Invalid expression type");
232             }
233
234             while (member != null)
235             {
236                 var property = (PropertyInfo)member.Member;
237                 if (builder.Length != 0)
238                 {
239                     if (!indexed)
240                         builder.Insert(0, ".");
241                     else
242                         indexed = false;
243                 }
244
245                 builder.Insert(0, property.Name);
246
247                 //                              member = member.Expression as MemberExpression ?? (member.Expression as UnaryExpression)?.Operand as MemberExpression;
248                 member = member.Expression as MemberExpression ?? (member.Expression is UnaryExpression ? (member.Expression as UnaryExpression).Operand as MemberExpression : null);
249             }
250
251             return builder.ToString();
252         }
253     }
254 }