[Xaml] Support Trigger in Xaml
authorFang Xiaohui <xiaohui.fang@samsung.com>
Fri, 20 Aug 2021 06:11:17 +0000 (14:11 +0800)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Wed, 1 Sep 2021 08:20:01 +0000 (17:20 +0900)
14 files changed:
src/Tizen.NUI/src/internal/Xaml/ApplyPropertiesVisitor.cs
src/Tizen.NUI/src/internal/Xaml/TypeConversionExtensions.cs
src/Tizen.NUI/src/internal/Xaml/VisualState/VisualState.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroup.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupList.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupListExtensions.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateManager.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualState/WatchAddList.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/Xaml/VisualStateManager.cs [deleted file]
src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs [new file with mode: 0755]
src/Tizen.NUI/src/internal/XamlBinding/StyleSheets/IStyle.cs [new file with mode: 0755]
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
src/Tizen.NUI/src/public/XamlBinding/ResourceDictionary.cs
src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs [new file with mode: 0755]

index 2d4bc90..f2ffb5d 100755 (executable)
@@ -166,7 +166,8 @@ namespace Tizen.NUI.Xaml
                     addMethod?.Invoke(source, new[] { value });
                     return;
                 }
-                if (xpe == null && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
+                if (xpe == null && Context.Types[parentElement].GetRuntimeMethods().Any
+                    (mi => mi.Name == "Add" && mi.GetParameters().Length == 1 && mi.GetParameters()[0].ParameterType.IsAssignableFrom(value.GetType())))
                 {
                     //if there are similar parameters in the function, this will exist issue.
                     var addMethod = Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
@@ -211,7 +212,7 @@ namespace Tizen.NUI.Xaml
                 MethodInfo addMethod;
                 if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null)
                 {
-                    addMethod.Invoke(collection, new[] { Values[node] });
+                    addMethod.Invoke(collection, new[] { value });
                     return;
                 }
                 xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
index fa6ff61..b0e25a5 100755 (executable)
@@ -93,7 +93,14 @@ namespace Tizen.NUI.Xaml
 
                 if (converterTypeName == null)
                 {
-                    converterTypeName = toType.FullName + "TypeConverter";
+                    if (toType == typeof(Type))
+                    {
+                        converterTypeName = typeof(TypeTypeConverter).FullName;
+                    }
+                    else
+                    {
+                        converterTypeName = toType.FullName + "TypeConverter";
+                    }
                 }
 
                 var convertertype = Type.GetType(converterTypeName);
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualState.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualState.cs
new file mode 100755 (executable)
index 0000000..de3ccd6
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    [RuntimeNameProperty(nameof(Name))]
+    internal sealed class VisualState
+    {
+        public VisualState()
+        {
+            Setters = new ObservableCollection<Setter>();
+        }
+
+        public string Name { get; set; }
+        public IList<Setter> Setters { get; }
+        public Type TargetType { get; set; }
+
+        internal VisualState Clone()
+        {
+            var clone = new VisualState { Name = Name, TargetType = TargetType };
+            foreach (var setter in Setters)
+            {
+                clone.Setters.Add(setter);
+            }
+
+            return clone;
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroup.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroup.cs
new file mode 100755 (executable)
index 0000000..d55184b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    [RuntimeNameProperty(nameof(Name))]
+    [ContentProperty(nameof(States))]
+    internal sealed class VisualStateGroup
+    {
+        public VisualStateGroup()
+        {
+            States = new WatchAddList<VisualState>(OnStatesChanged);
+        }
+
+        public Type TargetType { get; set; }
+        public string Name { get; set; }
+        public IList<VisualState> States { get; }
+        public VisualState CurrentState { get; internal set; }
+
+        internal VisualState GetState(string name)
+        {
+            foreach (VisualState state in States)
+            {
+                if (string.CompareOrdinal(state.Name, name) == 0)
+                {
+                    return state;
+                }
+            }
+
+            return null;
+        }
+
+        internal VisualStateGroup Clone()
+        {
+            var clone = new VisualStateGroup { TargetType = TargetType, Name = Name, CurrentState = CurrentState };
+            foreach (VisualState state in States)
+            {
+                clone.States.Add(state.Clone());
+            }
+
+            return clone;
+        }
+
+        internal event EventHandler StatesChanged;
+
+        void OnStatesChanged(IList<VisualState> list)
+        {
+            if (list.Any(state => string.IsNullOrEmpty(state.Name)))
+            {
+                throw new InvalidOperationException("State names may not be null or empty");
+            }
+
+            StatesChanged?.Invoke(this, EventArgs.Empty);
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupList.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupList.cs
new file mode 100755 (executable)
index 0000000..1faa931
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    internal class VisualStateGroupList : IList<VisualStateGroup>
+    {
+        readonly IList<VisualStateGroup> _internalList;
+
+        void Validate(IList<VisualStateGroup> groups)
+        {
+            // If we have 1 group, no need to worry about duplicate group names
+            if (groups.Count > 1)
+            {
+                if (groups.GroupBy(vsg => vsg.Name).Any(g => g.Count() > 1))
+                {
+                    throw new InvalidOperationException("VisualStateGroup Names must be unique");
+                }
+            }
+
+            // State names must be unique within this group list, so pull in all 
+            // the states in all the groups, group them by name, and see if we have
+            // and duplicates
+            if (groups.SelectMany(group => group.States).GroupBy(state => state.Name).Any(g => g.Count() > 1))
+            {
+                throw new InvalidOperationException("VisualState Names must be unique");
+            }
+        }
+
+        public VisualStateGroupList()
+        {
+            _internalList = new WatchAddList<VisualStateGroup>(Validate);
+        }
+
+        void ValidateOnStatesChanged(object sender, EventArgs eventArgs)
+        {
+            Validate(_internalList);
+        }
+
+        public IEnumerator<VisualStateGroup> GetEnumerator()
+        {
+            return _internalList.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((IEnumerable)_internalList).GetEnumerator();
+        }
+
+        public void Add(VisualStateGroup item)
+        {
+            _internalList.Add(item);
+            item.StatesChanged += ValidateOnStatesChanged;
+        }
+
+        public void Clear()
+        {
+            foreach (var group in _internalList)
+            {
+                group.StatesChanged -= ValidateOnStatesChanged;
+            }
+
+            _internalList.Clear();
+        }
+
+        public bool Contains(VisualStateGroup item)
+        {
+            return _internalList.Contains(item);
+        }
+
+        public void CopyTo(VisualStateGroup[] array, int arrayIndex)
+        {
+            _internalList.CopyTo(array, arrayIndex);
+        }
+
+        public bool Remove(VisualStateGroup item)
+        {
+            item.StatesChanged -= ValidateOnStatesChanged;
+            return _internalList.Remove(item);
+        }
+
+        public int Count => _internalList.Count;
+
+        public bool IsReadOnly => false;
+
+        public int IndexOf(VisualStateGroup item)
+        {
+            return _internalList.IndexOf(item);
+        }
+
+        public void Insert(int index, VisualStateGroup item)
+        {
+            item.StatesChanged += ValidateOnStatesChanged;
+            _internalList.Insert(index, item);
+        }
+
+        public void RemoveAt(int index)
+        {
+            _internalList[index].StatesChanged -= ValidateOnStatesChanged;
+            _internalList.RemoveAt(index);
+        }
+
+        public VisualStateGroup this[int index]
+        {
+            get => _internalList[index];
+            set => _internalList[index] = value;
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupListExtensions.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateGroupListExtensions.cs
new file mode 100755 (executable)
index 0000000..b25cb6a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    internal static class VisualStateGroupListExtensions
+    {
+        internal static IList<VisualStateGroup> Clone(this IList<VisualStateGroup> groups)
+        {
+            var actual = new VisualStateGroupList();
+            foreach (var group in groups)
+            {
+                actual.Add(group.Clone());
+            }
+
+            return actual;
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateManager.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/VisualStateManager.cs
new file mode 100755 (executable)
index 0000000..11d571d
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    internal static class VisualStateManager
+    {
+        internal class CommonStates
+        {
+            public const string Normal = "Normal";
+            public const string Disabled = "Disabled";
+            public const string Focused = "Focused";
+        }
+
+        private static VisualStateGroupList visualStateGroups;
+        public static readonly BindableProperty VisualStateGroupsProperty =
+            BindableProperty.CreateAttached("VisualStateGroups", typeof(VisualStateGroupList), typeof(/*VisualElement*/BaseHandle),
+                defaultValue: null, propertyChanged: VisualStateGroupsPropertyChanged,
+                defaultValueCreator: (BindableObject obj)=>
+                {
+                    if (null == visualStateGroups)
+                    {
+                        visualStateGroups = new VisualStateGroupList();
+                    }
+
+                    return visualStateGroups;
+                });
+
+        static void VisualStateGroupsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            GoToState((/*VisualElement*/BaseHandle)bindable, CommonStates.Normal);
+        }
+
+        public static IList<VisualStateGroup> GetVisualStateGroups(/*VisualElement*/BaseHandle visualElement)
+        {
+            return (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
+        }
+
+        public static void SetVisualStateGroups(/*VisualElement*/BaseHandle visualElement, VisualStateGroupList value)
+        {
+            visualElement.SetValue(VisualStateGroupsProperty, value);
+        }
+
+        public static bool GoToState(/*VisualElement*/BaseHandle visualElement, string name)
+        {
+            if (!visualElement.IsSet(VisualStateGroupsProperty))
+            {
+                return false;
+            }
+
+            var groups = (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
+
+            foreach (VisualStateGroup group in groups)
+            {
+                if (group.CurrentState?.Name == name)
+                {
+                    // We're already in the target state; nothing else to do
+                    return true;
+                }
+
+                // See if this group contains the new state
+                var target = group.GetState(name);
+                if (target == null)
+                {
+                    continue;
+                }
+
+                // If we've got a new state to transition to, unapply the setters from the current state
+                if (group.CurrentState != null)
+                {
+                    foreach (Setter setter in group.CurrentState.Setters)
+                    {
+                        setter.UnApply(visualElement);
+                    }
+                }
+
+                // Update the current state
+                group.CurrentState = target;
+
+                // Apply the setters from the new state
+                foreach (Setter setter in target.Setters)
+                {
+                    setter.Apply(visualElement);
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        public static bool HasVisualStateGroups(this /*VisualElement*/BaseHandle element)
+        {
+            return element.IsSet(VisualStateGroupsProperty);
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualState/WatchAddList.cs b/src/Tizen.NUI/src/internal/Xaml/VisualState/WatchAddList.cs
new file mode 100755 (executable)
index 0000000..cdff63f
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+    internal class WatchAddList<T> : IList<T>
+    {
+        readonly Action<List<T>> _onAdd;
+        readonly List<T> _internalList;
+
+        public WatchAddList(Action<List<T>> onAdd)
+        {
+            _onAdd = onAdd;
+            _internalList = new List<T>();
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return _internalList.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((IEnumerable)_internalList).GetEnumerator();
+        }
+
+        public void Add(T item)
+        {
+            _internalList.Add(item);
+            _onAdd(_internalList);
+        }
+
+        public void Clear()
+        {
+            _internalList.Clear();
+        }
+
+        public bool Contains(T item)
+        {
+            return _internalList.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            _internalList.CopyTo(array, arrayIndex);
+        }
+
+        public bool Remove(T item)
+        {
+            return _internalList.Remove(item);
+        }
+
+        public int Count => _internalList.Count;
+
+        public bool IsReadOnly => false;
+
+        public int IndexOf(T item)
+        {
+            return _internalList.IndexOf(item);
+        }
+
+        public void Insert(int index, T item)
+        {
+            _internalList.Insert(index, item);
+            _onAdd(_internalList);
+        }
+
+        public void RemoveAt(int index)
+        {
+            _internalList.RemoveAt(index);
+        }
+
+        public T this[int index]
+        {
+            get => _internalList[index];
+            set => _internalList[index] = value;
+        }
+    }
+}
diff --git a/src/Tizen.NUI/src/internal/Xaml/VisualStateManager.cs b/src/Tizen.NUI/src/internal/Xaml/VisualStateManager.cs
deleted file mode 100755 (executable)
index e13521e..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright(c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using Tizen.NUI;
-using Tizen.NUI.Binding;
-
-namespace Tizen.NUI.Xaml
-{
-    internal static class VisualStateManager
-    {
-        internal class CommonStates
-        {
-            public const string Normal = "Normal";
-            public const string Disabled = "Disabled";
-            public const string Focused = "Focused";
-        }
-
-        public static readonly BindableProperty VisualStateGroupsProperty =
-            BindableProperty.CreateAttached("VisualStateGroups", typeof(VisualStateGroupList), typeof(/*VisualElement*/BaseHandle),
-                defaultValue: null, propertyChanged: VisualStateGroupsPropertyChanged,
-                defaultValueCreator: bindable => new VisualStateGroupList());
-
-        static void VisualStateGroupsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
-        {
-            GoToState((/*VisualElement*/BaseHandle)bindable, CommonStates.Normal);
-        }
-
-        public static IList<VisualStateGroup> GetVisualStateGroups(/*VisualElement*/BaseHandle visualElement)
-        {
-            return (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
-        }
-
-        public static void SetVisualStateGroups(/*VisualElement*/BaseHandle visualElement, VisualStateGroupList value)
-        {
-            visualElement.SetValue(VisualStateGroupsProperty, value);
-        }
-
-        public static bool GoToState(/*VisualElement*/BaseHandle visualElement, string name)
-        {
-            if (!visualElement.IsSet(VisualStateGroupsProperty))
-            {
-                return false;
-            }
-
-            var groups = (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
-
-            foreach (VisualStateGroup group in groups)
-            {
-                if (group.CurrentState?.Name == name)
-                {
-                    // We're already in the target state; nothing else to do
-                    return true;
-                }
-
-                // See if this group contains the new state
-                var target = group.GetState(name);
-                if (target == null)
-                {
-                    continue;
-                }
-
-                // If we've got a new state to transition to, unapply the setters from the current state
-                if (group.CurrentState != null)
-                {
-                    foreach (Setter setter in group.CurrentState.Setters)
-                    {
-                        setter.UnApply(visualElement);
-                    }
-                }
-
-                // Update the current state
-                group.CurrentState = target;
-
-                // Apply the setters from the new state
-                foreach (Setter setter in target.Setters)
-                {
-                    setter.Apply(visualElement);
-                }
-
-                return true;
-            }
-
-            return false;
-        }
-
-        public static bool HasVisualStateGroups(this /*VisualElement*/BaseHandle element)
-        {
-            return element.IsSet(VisualStateGroupsProperty);
-        }
-    }
-
-    internal class VisualStateGroupList : IList<VisualStateGroup>
-    {
-        readonly IList<VisualStateGroup> _internalList;
-
-        void Validate(IList<VisualStateGroup> groups)
-        {
-            // If we have 1 group, no need to worry about duplicate group names
-            if (groups.Count > 1)
-            {
-                if (groups.GroupBy(vsg => vsg.Name).Any(g => g.Count() > 1))
-                {
-                    throw new InvalidOperationException("VisualStateGroup Names must be unique");
-                }
-            }
-
-            // State names must be unique within this group list, so pull in all 
-            // the states in all the groups, group them by name, and see if we have
-            // and duplicates
-            if (groups.SelectMany(group => group.States)
-                .GroupBy(state => state.Name)
-                .Any(g => g.Count() > 1))
-            {
-                throw new InvalidOperationException("VisualState Names must be unique");
-            }
-        }
-
-        public VisualStateGroupList()
-        {
-            _internalList = new WatchAddList<VisualStateGroup>(Validate);
-        }
-
-        void ValidateOnStatesChanged(object sender, EventArgs eventArgs)
-        {
-            Validate(_internalList);
-        }
-
-        public IEnumerator<VisualStateGroup> GetEnumerator()
-        {
-            return _internalList.GetEnumerator();
-        }
-
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return ((IEnumerable)_internalList).GetEnumerator();
-        }
-
-        public void Add(VisualStateGroup item)
-        {
-            _internalList.Add(item);
-            item.StatesChanged += ValidateOnStatesChanged;
-        }
-
-        public void Clear()
-        {
-            foreach (var group in _internalList)
-            {
-                group.StatesChanged -= ValidateOnStatesChanged;
-            }
-
-            _internalList.Clear();
-        }
-
-        public bool Contains(VisualStateGroup item)
-        {
-            return _internalList.Contains(item);
-        }
-
-        public void CopyTo(VisualStateGroup[] array, int arrayIndex)
-        {
-            _internalList.CopyTo(array, arrayIndex);
-        }
-
-        public bool Remove(VisualStateGroup item)
-        {
-            item.StatesChanged -= ValidateOnStatesChanged;
-            return _internalList.Remove(item);
-        }
-
-        public int Count => _internalList.Count;
-
-        public bool IsReadOnly => false;
-
-        public int IndexOf(VisualStateGroup item)
-        {
-            return _internalList.IndexOf(item);
-        }
-
-        public void Insert(int index, VisualStateGroup item)
-        {
-            item.StatesChanged += ValidateOnStatesChanged;
-            _internalList.Insert(index, item);
-        }
-
-        public void RemoveAt(int index)
-        {
-            _internalList[index].StatesChanged -= ValidateOnStatesChanged;
-            _internalList.RemoveAt(index);
-        }
-
-        public VisualStateGroup this[int index]
-        {
-            get => _internalList[index];
-            set => _internalList[index] = value;
-        }
-    }
-
-    [RuntimeNameProperty(nameof(Name))]
-    [ContentProperty(nameof(States))]
-    internal sealed class VisualStateGroup
-    {
-        public VisualStateGroup()
-        {
-            States = new WatchAddList<VisualState>(OnStatesChanged);
-        }
-
-        public Type TargetType { get; set; }
-        public string Name { get; set; }
-        public IList<VisualState> States { get; }
-        public VisualState CurrentState { get; internal set; }
-
-        internal VisualState GetState(string name)
-        {
-            foreach (VisualState state in States)
-            {
-                if (string.CompareOrdinal(state.Name, name) == 0)
-                {
-                    return state;
-                }
-            }
-
-            return null;
-        }
-
-        internal VisualStateGroup Clone()
-        {
-            var clone = new VisualStateGroup { TargetType = TargetType, Name = Name, CurrentState = CurrentState };
-            foreach (VisualState state in States)
-            {
-                clone.States.Add(state.Clone());
-            }
-
-            return clone;
-        }
-
-        internal event EventHandler StatesChanged;
-
-        void OnStatesChanged(IList<VisualState> list)
-        {
-            if (list.Any(state => string.IsNullOrEmpty(state.Name)))
-            {
-                throw new InvalidOperationException("State names may not be null or empty");
-            }
-
-            StatesChanged?.Invoke(this, EventArgs.Empty);
-        }
-    }
-
-    [RuntimeNameProperty(nameof(Name))]
-    internal sealed class VisualState
-    {
-        public VisualState()
-        {
-            Setters = new ObservableCollection<Setter>();
-        }
-
-        public string Name { get; set; }
-        public IList<Setter> Setters { get; }
-        public Type TargetType { get; set; }
-
-        internal VisualState Clone()
-        {
-            var clone = new VisualState { Name = Name, TargetType = TargetType };
-            foreach (var setter in Setters)
-            {
-                clone.Setters.Add(setter);
-            }
-
-            return clone;
-        }
-    }
-
-    internal static class VisualStateGroupListExtensions
-    {
-        internal static IList<VisualStateGroup> Clone(this IList<VisualStateGroup> groups)
-        {
-            var actual = new VisualStateGroupList();
-            foreach (var group in groups)
-            {
-                actual.Add(group.Clone());
-            }
-
-            return actual;
-        }
-    }
-
-    internal class WatchAddList<T> : IList<T>
-    {
-        readonly Action<List<T>> _onAdd;
-        readonly List<T> _internalList;
-
-        public WatchAddList(Action<List<T>> onAdd)
-        {
-            _onAdd = onAdd;
-            _internalList = new List<T>();
-        }
-
-        public IEnumerator<T> GetEnumerator()
-        {
-            return _internalList.GetEnumerator();
-        }
-
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return ((IEnumerable)_internalList).GetEnumerator();
-        }
-
-        public void Add(T item)
-        {
-            _internalList.Add(item);
-            _onAdd(_internalList);
-        }
-
-        public void Clear()
-        {
-            _internalList.Clear();
-        }
-
-        public bool Contains(T item)
-        {
-            return _internalList.Contains(item);
-        }
-
-        public void CopyTo(T[] array, int arrayIndex)
-        {
-            _internalList.CopyTo(array, arrayIndex);
-        }
-
-        public bool Remove(T item)
-        {
-            return _internalList.Remove(item);
-        }
-
-        public int Count => _internalList.Count;
-
-        public bool IsReadOnly => false;
-
-        public int IndexOf(T item)
-        {
-            return _internalList.IndexOf(item);
-        }
-
-        public void Insert(int index, T item)
-        {
-            _internalList.Insert(index, item);
-            _onAdd(_internalList);
-        }
-
-        public void RemoveAt(int index)
-        {
-            _internalList.RemoveAt(index);
-        }
-
-        public T this[int index]
-        {
-            get => _internalList[index];
-            set => _internalList[index] = value;
-        }
-    }
-}
diff --git a/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs b/src/Tizen.NUI/src/internal/XamlBinding/MergedStyle.cs
new file mode 100755 (executable)
index 0000000..bf0c29b
--- /dev/null
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.StyleSheets;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI.Binding
+{
+    internal sealed class MergedStyle : IStyle
+    {
+        ////If the base type is one of these, stop registering dynamic resources further
+        ////The last one (typeof(Element)) is a safety guard as we might be creating VisualElement directly in internal code
+        static readonly IList<Type> s_stopAtTypes = new List<Type> { typeof(View), typeof(Element) };
+
+        IList<BindableProperty> _classStyleProperties;
+
+        readonly List<BindableProperty> _implicitStyles = new List<BindableProperty>();
+
+        IList<XamlStyle> _classStyles;
+
+        IStyle _implicitStyle;
+
+        IStyle _style;
+
+        IList<string> _styleClass;
+
+        public MergedStyle(Type targetType, BindableObject target)
+        {
+            Target = target;
+            TargetType = targetType;
+            RegisterImplicitStyles();
+            Apply(Target);
+        }
+
+        public IStyle Style
+        {
+            get { return _style; }
+            set { SetStyle(ImplicitStyle, ClassStyles, value); }
+        }
+
+        public IList<string> StyleClass
+        {
+            get { return _styleClass; }
+            set
+            {
+                if (_styleClass == value)
+                    return;
+
+                if (_styleClass != null && _classStyles != null)
+                    foreach (var classStyleProperty in _classStyleProperties)
+                        Target.RemoveDynamicResource(classStyleProperty);
+
+                _styleClass = value;
+
+                if (_styleClass != null)
+                {
+                    _classStyleProperties = new List<BindableProperty>();
+                    foreach (var styleClass in _styleClass)
+                    {
+                        var classStyleProperty = BindableProperty.Create("ClassStyle", typeof(IList<XamlStyle>), typeof(View), default(IList<XamlStyle>),
+                            propertyChanged: (bindable, oldvalue, newvalue) => ((View)bindable)._mergedStyle.OnClassStyleChanged());
+                        _classStyleProperties.Add(classStyleProperty);
+                        Target.OnSetDynamicResource(classStyleProperty, Tizen.NUI.Binding.XamlStyle.StyleClassPrefix + styleClass);
+                    }
+                }
+            }
+        }
+
+        public BindableObject Target { get; }
+
+        IList<XamlStyle> ClassStyles
+        {
+            get { return _classStyles; }
+            set { SetStyle(ImplicitStyle, value, Style); }
+        }
+
+        IStyle ImplicitStyle
+        {
+            get { return _implicitStyle; }
+            set { SetStyle(value, ClassStyles, Style); }
+        }
+
+        public void Apply(BindableObject bindable)
+        {
+            ImplicitStyle?.Apply(bindable);
+            if (ClassStyles != null)
+                foreach (var classStyle in ClassStyles)
+                    ((IStyle)classStyle)?.Apply(bindable);
+            Style?.Apply(bindable);
+        }
+
+        public Type TargetType { get; }
+
+        public void UnApply(BindableObject bindable)
+        {
+            Style?.UnApply(bindable);
+            if (ClassStyles != null)
+                foreach (var classStyle in ClassStyles)
+                    ((IStyle)classStyle)?.UnApply(bindable);
+            ImplicitStyle?.UnApply(bindable);
+        }
+
+        void OnClassStyleChanged()
+        {
+            ClassStyles = _classStyleProperties.Select(p => (Target.GetValue(p) as IList<XamlStyle>)?.FirstOrDefault(s => s.CanBeAppliedTo(TargetType))).ToList();
+        }
+
+        void OnImplicitStyleChanged()
+        {
+            var first = true;
+            foreach (BindableProperty implicitStyleProperty in _implicitStyles)
+            {
+                var implicitStyle = (XamlStyle)Target.GetValue(implicitStyleProperty);
+                if (implicitStyle != null)
+                {
+                    if (first || implicitStyle.ApplyToDerivedTypes)
+                    {
+                        ImplicitStyle = implicitStyle;
+                        return;
+                    }
+                }
+                first = false;
+            }
+        }
+
+        void RegisterImplicitStyles()
+        {
+            Type type = TargetType;
+            if (type == null)
+            {
+                return;
+            }
+            while (true)
+            {
+                BindableProperty implicitStyleProperty = BindableProperty.Create(nameof(ImplicitStyle), typeof(XamlStyle), typeof(View), default(XamlStyle),
+                        propertyChanged: (bindable, oldvalue, newvalue) => OnImplicitStyleChanged());
+                _implicitStyles.Add(implicitStyleProperty);
+                Target.SetDynamicResource(implicitStyleProperty, type.FullName);
+                type = type.GetTypeInfo().BaseType;
+                if (s_stopAtTypes.Contains(type))
+                    return;
+            }
+        }
+
+        void SetStyle(IStyle implicitStyle, IList<XamlStyle> classStyles, IStyle style)
+        {
+            bool shouldReApplyStyle = implicitStyle != ImplicitStyle || classStyles != ClassStyles || Style != style;
+            bool shouldReApplyClassStyle = implicitStyle != ImplicitStyle || classStyles != ClassStyles;
+            bool shouldReApplyImplicitStyle = implicitStyle != ImplicitStyle && (Style as XamlStyle == null || ((XamlStyle)Style).CanCascade);
+
+            if (shouldReApplyStyle)
+                Style?.UnApply(Target);
+            if (shouldReApplyClassStyle && ClassStyles != null)
+                foreach (var classStyle in ClassStyles)
+                    ((IStyle)classStyle)?.UnApply(Target);
+            if (shouldReApplyImplicitStyle)
+                ImplicitStyle?.UnApply(Target);
+
+            _implicitStyle = implicitStyle;
+            _classStyles = classStyles;
+            _style = style;
+
+            if (shouldReApplyImplicitStyle)
+                ImplicitStyle?.Apply(Target);
+            if (shouldReApplyClassStyle && ClassStyles != null)
+                foreach (var classStyle in ClassStyles)
+                    ((IStyle)classStyle)?.Apply(Target);
+            if (shouldReApplyStyle)
+                Style?.Apply(Target);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/internal/XamlBinding/StyleSheets/IStyle.cs b/src/Tizen.NUI/src/internal/XamlBinding/StyleSheets/IStyle.cs
new file mode 100755 (executable)
index 0000000..1cb59e3
--- /dev/null
@@ -0,0 +1,13 @@
+using System;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+    internal interface IStyle
+    {
+        Type TargetType { get; }
+
+        void Apply(BindableObject bindable);
+        void UnApply(BindableObject bindable);
+    }
+}
index dcc758f..f40cd3c 100755 (executable)
@@ -20,6 +20,7 @@ using System.Collections.Generic;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using Tizen.NUI.Binding;
 
 namespace Tizen.NUI.BaseComponents
 {
@@ -29,8 +30,22 @@ namespace Tizen.NUI.BaseComponents
     /// <since_tizen> 3 </since_tizen>
     public partial class View
     {
+        private MergedStyle mergedStyle = null;
         internal string styleName;
 
+        internal MergedStyle _mergedStyle
+        {
+            get
+            {
+                if (null == mergedStyle)
+                {
+                    mergedStyle = new MergedStyle(GetType(), this);
+                }
+
+                return mergedStyle;
+            }
+        }
+
         internal class ThemeData
         {
             [Flags]
index 9b34cd0..797436b 100755 (executable)
@@ -343,6 +343,21 @@ namespace Tizen.NUI.Binding
             remove { ValuesChanged -= value; }
         }
 
+        internal void Add(XamlStyle style)
+        {
+            if (string.IsNullOrEmpty(style.Class))
+                Add(style.TargetType.FullName, style);
+            else
+            {
+                IList<XamlStyle> classes;
+                object outclasses;
+                if (!TryGetValue(XamlStyle.StyleClassPrefix + style.Class, out outclasses) || (classes = outclasses as IList<XamlStyle>) == null)
+                    classes = new List<XamlStyle>();
+                classes.Add(style);
+                this[XamlStyle.StyleClassPrefix + style.Class] = classes;
+            }
+        }
+
         /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
         [EditorBrowsable(EditorBrowsableState.Never)]
         public void Add(ResourceDictionary mergedResourceDictionary)
diff --git a/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs b/src/Tizen.NUI/src/public/XamlBinding/XamlStyle.cs
new file mode 100755 (executable)
index 0000000..c8f0fad
--- /dev/null
@@ -0,0 +1,212 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Tizen.NUI.StyleSheets;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+    /// <since_tizen> 6 </since_tizen>
+    /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    [ContentProperty("Setters")]
+    public sealed class XamlStyle : IStyle
+    {
+        internal const string StyleClassPrefix = "Tizen.NUI.Binding.StyleClass.";
+
+        readonly BindableProperty _basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(XamlStyle), typeof(XamlStyle), default(XamlStyle),
+            propertyChanged: OnBasedOnResourceChanged);
+
+        readonly List<WeakReference<BindableObject>> _targets = new List<WeakReference<BindableObject>>(4);
+
+        XamlStyle _basedOnStyle;
+
+        string _baseResourceKey;
+
+        IList<Behavior> _behaviors;
+
+        IList<TriggerBase> _triggers;
+
+        /// <since_tizen> 6 </since_tizen>
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public XamlStyle([TypeConverter(typeof(TypeTypeConverter))][Parameter("TargetType")] Type targetType)
+        {
+            if (targetType == null)
+                throw new ArgumentNullException(nameof(targetType));
+
+            TargetType = targetType;
+            Setters = new List<Setter>();
+        }
+
+        /// <since_tizen> 6 </since_tizen>
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool ApplyToDerivedTypes { get; set; }
+
+        /// <since_tizen> 6 </since_tizen>
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public XamlStyle BasedOn
+        {
+            get { return _basedOnStyle; }
+            set
+            {
+                if (_basedOnStyle == value)
+                    return;
+                if (!ValidateBasedOn(value))
+                    throw new ArgumentException("BasedOn.TargetType is not compatible with TargetType");
+                XamlStyle oldValue = _basedOnStyle;
+                _basedOnStyle = value;
+                BasedOnChanged(oldValue, value);
+                if (value != null)
+                    BaseResourceKey = null;
+            }
+        }
+
+        /// <since_tizen> 6 </since_tizen>
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string BaseResourceKey
+        {
+            get { return _baseResourceKey; }
+            set
+            {
+                if (_baseResourceKey == value)
+                    return;
+                _baseResourceKey = value;
+                //update all DynamicResources
+                foreach (WeakReference<BindableObject> bindableWr in _targets)
+                {
+                    BindableObject target;
+                    if (!bindableWr.TryGetTarget(out target))
+                        continue;
+                    target.RemoveDynamicResource(_basedOnResourceProperty);
+                    if (value != null)
+                        target.SetDynamicResource(_basedOnResourceProperty, value);
+                }
+                if (value != null)
+                    BasedOn = null;
+            }
+        }
+
+        internal IList<Behavior> Behaviors
+        {
+            get { return _behaviors ?? (_behaviors = new AttachedCollection<Behavior>()); }
+        }
+
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool CanCascade { get; set; }
+
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public string Class { get; set; }
+
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IList<Setter> Setters { get; }
+
+        /// This will be public opened in tizen_next after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IList<TriggerBase> Triggers
+        {
+            get { return _triggers ?? (_triggers = new AttachedCollection<TriggerBase>()); }
+        }
+
+        void IStyle.Apply(BindableObject bindable)
+        {
+            _targets.Add(new WeakReference<BindableObject>(bindable));
+            if (BaseResourceKey != null)
+                bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey);
+            ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+        }
+
+        /// <since_tizen> 6 </since_tizen>
+        /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Type TargetType { get; }
+
+        void IStyle.UnApply(BindableObject bindable)
+        {
+            UnApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+            bindable.RemoveDynamicResource(_basedOnResourceProperty);
+            _targets.RemoveAll(wr =>
+            {
+                BindableObject target;
+                return wr.TryGetTarget(out target) && target == bindable;
+            });
+        }
+
+        internal bool CanBeAppliedTo(Type targetType)
+        {
+            if (TargetType == targetType)
+                return true;
+            if (!ApplyToDerivedTypes)
+                return false;
+            do
+            {
+                targetType = targetType.GetTypeInfo().BaseType;
+                if (TargetType == targetType)
+                    return true;
+            } while (targetType != typeof(Element));
+            return false;
+        }
+
+        void ApplyCore(BindableObject bindable, XamlStyle basedOn)
+        {
+            if (basedOn != null)
+                ((IStyle)basedOn).Apply(bindable);
+
+            foreach (Setter setter in Setters)
+                setter.Apply(bindable, true);
+            ((AttachedCollection<Behavior>)Behaviors).AttachTo(bindable);
+            ((AttachedCollection<TriggerBase>)Triggers).AttachTo(bindable);
+        }
+
+        void BasedOnChanged(XamlStyle oldValue, XamlStyle newValue)
+        {
+            foreach (WeakReference<BindableObject> bindableRef in _targets)
+            {
+                BindableObject bindable;
+                if (!bindableRef.TryGetTarget(out bindable))
+                    continue;
+
+                UnApplyCore(bindable, oldValue);
+                ApplyCore(bindable, newValue);
+            }
+        }
+
+        XamlStyle GetBasedOnResource(BindableObject bindable)
+        {
+            return (XamlStyle)bindable.GetValue(_basedOnResourceProperty);
+        }
+
+        static void OnBasedOnResourceChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            // Style style = (bindable as /*VisualElement*/BaseHandle).Style;
+            // if (style == null)
+            //         return;
+            // style.UnApplyCore(bindable, (Style)oldValue);
+            // style.ApplyCore(bindable, (Style)newValue);
+        }
+
+        void UnApplyCore(BindableObject bindable, XamlStyle basedOn)
+        {
+            ((AttachedCollection<TriggerBase>)Triggers).DetachFrom(bindable);
+            ((AttachedCollection<Behavior>)Behaviors).DetachFrom(bindable);
+            foreach (Setter setter in Setters)
+                setter.UnApply(bindable, true);
+
+            if (basedOn != null)
+                ((IStyle)basedOn).UnApply(bindable);
+        }
+
+        bool ValidateBasedOn(XamlStyle value)
+        {
+            if (value == null)
+                return true;
+            return value.TargetType.IsAssignableFrom(TargetType);
+        }
+    }
+}