[NUI] Make BindableObject.IsBound public.
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / Binding.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Globalization;
22 using System.Linq;
23 using System.Linq.Expressions;
24 using System.Reflection;
25 using System.Text;
26 using System.Diagnostics.CodeAnalysis;
27
28 namespace Tizen.NUI.Binding
29 {
30     /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
31     [SuppressMessage("Microsoft.Design", "CA1724: Type names should not match namespaces")]
32     [EditorBrowsable(EditorBrowsableState.Never)]
33     public sealed class Binding : BindingBase
34     {
35         internal const string SelfPath = ".";
36         IValueConverter converter;
37         object converterParameter;
38
39         BindingExpression expression;
40         string path;
41         object source;
42         string updateSourceEventName;
43
44         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
45         [EditorBrowsable(EditorBrowsableState.Never)]
46         public Binding()
47         {
48         }
49
50         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public Binding(string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null, string stringFormat = null, object source = null)
53         {
54             if (path == null)
55                 throw new ArgumentNullException(nameof(path));
56             if (string.IsNullOrWhiteSpace(path))
57                 throw new ArgumentException("path can not be an empty string", nameof(path));
58
59             Path = path;
60             Converter = converter;
61             ConverterParameter = converterParameter;
62             Mode = mode;
63             StringFormat = stringFormat;
64             Source = source;
65         }
66
67         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
68         [EditorBrowsable(EditorBrowsableState.Never)]
69         public IValueConverter Converter
70         {
71             get { return converter; }
72             set
73             {
74                 ThrowIfApplied();
75
76                 converter = value;
77             }
78         }
79
80         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         public object ConverterParameter
83         {
84             get { return converterParameter; }
85             set
86             {
87                 ThrowIfApplied();
88
89                 converterParameter = value;
90             }
91         }
92
93         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
94         [EditorBrowsable(EditorBrowsableState.Never)]
95         public string Path
96         {
97             get { return path; }
98             set
99             {
100                 ThrowIfApplied();
101
102                 path = value;
103                 expression = new BindingExpression(this, !string.IsNullOrWhiteSpace(value) ? value : SelfPath);
104             }
105         }
106
107         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
108         [EditorBrowsable(EditorBrowsableState.Never)]
109         public object Source
110         {
111             get { return source; }
112             set
113             {
114                 ThrowIfApplied();
115                 source = value;
116
117                 if (source is BindableObject bindableObject)
118                 {
119                     bindableObject.IsBound = true;
120                 }
121             }
122         }
123
124         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
125         [EditorBrowsable(EditorBrowsableState.Never)]
126         public string UpdateSourceEventName
127         {
128             get { return updateSourceEventName; }
129             set
130             {
131                 ThrowIfApplied();
132                 updateSourceEventName = value;
133             }
134         }
135
136         internal override void Apply(bool fromTarget)
137         {
138             base.Apply(fromTarget);
139
140             if (expression == null)
141                 expression = new BindingExpression(this, SelfPath);
142
143             expression.Apply(fromTarget);
144         }
145
146         internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
147         {
148             object src = source;
149             var isApplied = IsApplied;
150
151             base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
152
153             if (src != null && isApplied && fromBindingContextChanged)
154                 return;
155
156             object bindingContext = src ?? Context ?? newContext;
157             if (expression == null && bindingContext != null)
158                 expression = new BindingExpression(this, SelfPath);
159
160             expression?.Apply(bindingContext, bindObj, targetProperty);
161         }
162
163         internal override BindingBase Clone()
164         {
165             return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
166         }
167
168         internal override object GetSourceValue(object value, Type targetPropertyType)
169         {
170             if (Converter != null)
171                 value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
172
173             return base.GetSourceValue(value, targetPropertyType);
174         }
175
176         internal override object GetTargetValue(object value, Type sourcePropertyType)
177         {
178             if (Converter != null)
179                 value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
180
181             return base.GetTargetValue(value, sourcePropertyType);
182         }
183
184         internal override void Unapply(bool fromBindingContextChanged = false)
185         {
186             if (Source != null && fromBindingContextChanged && IsApplied)
187                 return;
188
189             base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
190
191             if (expression != null)
192                 expression.Unapply();
193         }
194     }
195 }