Skip to content

Commit

Permalink
[NUI] Introduce new binding style.
Browse files Browse the repository at this point in the history
The binding in NUI cause performance and memory issue,
so we plan to deprecate them by setting IsUsingXaml disable.

This patch is aim to introduce new style of binding,
which do not causing performance and memory seriously,
and user can add binding property on existing view class,
so that we do not need to add every property to bindable.
  • Loading branch information
everLEEst authored and dongsug-song committed Feb 21, 2025
1 parent eaa22c3 commit 3995d1d
Show file tree
Hide file tree
Showing 7 changed files with 649 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ protected override void OnEnabled(bool enabled)
protected override void OnBindingContextChanged()
{
PropagateBindingContext(this);
base.OnBindingContextChanged();
}

private void PropagateBindingContext(View parent)
Expand Down
207 changes: 207 additions & 0 deletions src/Tizen.NUI/src/devel/Binding/BindingExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
using System;
using System.ComponentModel;
using System.Reflection;
using Tizen.NUI.BaseComponents;

namespace Tizen.NUI.Binding
{
/// <summary>
/// Provides extension methods for binding properties of a view model to a view.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class BindingExtensions
{
/// <summary>
/// Sets the binding for the specified view model property.
/// </summary>
/// <typeparam name="T">The type of the view model.</typeparam>
/// <typeparam name="TView">The type of the view.</typeparam>
/// <param name="view">The view to bind to.</param>
/// <param name="vm">The view model to bind from.</param>
/// <param name="set">The action to set the view property.</param>
/// <param name="path">The path of the view model property.</param>
/// <returns>The view.</returns>
public static TView SetBinding<T, TView>(this TView view, BindingSession<T> vm, Action<T, TView> set, string path) where TView : View
{
_ = view ?? throw new ArgumentNullException(nameof(view));

var setter = new Action<T>(vm =>
{
set.Invoke(vm, view);
});
vm.AddBinding(setter, path);
return view;
}

/// <summary>
/// Sets the binding for the specified view model property.
/// </summary>
/// <typeparam name="T">The type of the view model.</typeparam>
/// <param name="view">The view to bind to.</param>
/// <param name="vm">The view model to bind from.</param>
/// <param name="set">The action to set the view property.</param>
/// <param name="path">The path of the view model property.</param>
/// <returns>The view.</returns>
public static View SetBinding<T>(this View view, BindingSession<T> vm, Action<T> set, string path)
{
vm.AddBinding(set, path);
return view;
}

/// <summary>
/// Sets the binding for the specified view model property.
/// </summary>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
/// <param name="view">The view to bind to.</param>
/// <param name="session">The binding session.</param>
/// <param name="targetPath">The path of the view property.</param>
/// <param name="srcPath">The path of the view model property.</param>
/// <returns>The view.</returns>
public static View SetBinding<TViewModel>(this View view, BindingSession<TViewModel> session, string targetPath, string srcPath)
{
var setter = new Action<TViewModel>(model =>
{
if (view.Disposed)
{
return;
}
var prop = view.GetType().GetProperty(targetPath, BindingFlags.Public | BindingFlags.Instance);
prop.SetValue(view, session.GetValue(srcPath));
});
session.AddBinding(setter, srcPath);
return view;
}

/// <summary>
/// Sets the binding for the specified view model property.
/// </summary>
/// <typeparam name="TView">The type of the view.</typeparam>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
/// <typeparam name="TProperty">The type of the view property.</typeparam>
/// <param name="view">The view to bind to.</param>
/// <param name="session">The binding session.</param>
/// <param name="property">The view property.</param>
/// <param name="path">The path of the view model property.</param>
/// <returns>The view.</returns>
public static TView SetBinding<TView, TViewModel, TProperty>(this TView view, BindingSession<TViewModel> session, BindingProperty<TView, TProperty> property, string path) where TView : View
{
var setter = new Action<TViewModel>(model =>
{
if (view.Disposed)
{
return;
}

var value = session.GetValue(path);
// need to apply convertor if type was not mached
if (value != null && !typeof(TProperty).IsAssignableFrom(value.GetType()))
{
// only string type convert with ToString()
if (typeof(TProperty) == typeof(string))
{
value = value.ToString();
}
else
{
throw new InvalidCastException($"Cannot cast {value.GetType()} to {typeof(TProperty)}");
}
}
property.Setter(view, (TProperty)value);
});
session.AddBinding(setter, path);
return view;
}

/// <summary>
/// Sets the two-way binding for the specified view model property.
/// </summary>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
/// <typeparam name="TProperty">The type of the view property.</typeparam>
/// <param name="view">The view to bind to.</param>
/// <param name="session">The binding session.</param>
/// <param name="property">The view property.</param>
/// <param name="path">The path of the view model property.</param>
/// <returns>The view.</returns>
public static View SetTwoWayBinding<TViewModel, TProperty>(this View view, BindingSession<TViewModel> session, TwoWayBindingProperty<View, TProperty> property, string path)
{
var regit = new Action<Action>(act =>
{
property.AddObserver(view, act);
});
var unregit = new Action<Action>(act =>
{
property.RemoveObserver(view, act);
});
var setter = new Action<TViewModel>(model =>
{
if (view.Disposed)
{
return;
}
property.Setter(view, (TProperty)session.GetValue(path));
});
var getter = new Func<TProperty>(() => property.Getter(view));
session.AddTwoWayBinding(regit, unregit, setter, getter, path);
return view;
}

/// <summary>
/// Sets the two-way binding for the specified view model property.
/// </summary>
/// <typeparam name="TView">The type of the view.</typeparam>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
/// <typeparam name="TProperty">The type of the view property.</typeparam>
/// <param name="view">The to.</param>
/// <param name="session">The binding session.</param>
/// <param name="property">The view property.</param>
/// <param name="path">The path of the view model property.</param>
/// <returns>The view.</returns>
public static TView SetTwoWayBinding<TView, TViewModel, TProperty>(this TView view, BindingSession<TViewModel> session, TwoWayBindingProperty<TView, TProperty> property, string path) where TView : View
{
var regit = new Action<Action>(act =>
{
property.AddObserver(view, act);
});
var unregit = new Action<Action>(act =>
{
property.RemoveObserver(view, act);
});
var setter = new Action<TViewModel>(model =>
{
if (view.Disposed)
{
return;
}
property.Setter(view, (TProperty)session.GetValue(path));
});
var getter = new Func<TProperty>(() => property.Getter(view));
session.AddTwoWayBinding(regit, unregit, setter, getter, path);
return view;
}

/// <summary>
/// Gets the binding session for the specified view.
/// </summary>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
/// <param name="view">The view.</param>
/// <returns>The binding session.</returns>
public static BindingSession<TViewModel> BindingSession<TViewModel>(this View view)
{
return view.GetAttached<BindingSession<TViewModel>>();
}

/// <summary>
/// Sets the binding session for the specified view.
/// </summary>
/// <typeparam name="T">The type of the view model.</typeparam>
/// <typeparam name="TViewModel">The type of the view.</typeparam>
/// <param name="view">The view.</param>
/// <param name="session">The binding session.</param>
/// <returns>The view.</returns>
public static T BindingSession<T, TViewModel>(this T view, BindingSession<TViewModel> session) where T : View
{
view.SetAttached(session);
return view;
}
}
}
19 changes: 19 additions & 0 deletions src/Tizen.NUI/src/devel/Binding/BindingProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.ComponentModel;

namespace Tizen.NUI.Binding
{
/// <summary>
/// The BindingProperty class represents a binding property for a view.
/// </summary>
/// <typeparam name="TView">The type of the view.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public class BindingProperty<TView, TValue>
{
/// <summary>
/// Gets or sets the setter action for the binding property.
/// </summary>
public Action<TView, TValue> Setter { get; set; }
}
}
Loading

0 comments on commit 3995d1d

Please sign in to comment.