summaryrefslogtreecommitdiff
path: root/src/bindings/mono/efl_mono/UserModel.cs
blob: 99350b135a73bb5cea2a0e56f3ceba58b1fd1ac2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Reflection;

namespace Efl {

#if EFL_BETA

internal class ModelHelper
{
    /// FIXME Move this to eina_value.cs and be a static method of Value?
    static internal Eina.Value ValueFromProperty<T>(T source, PropertyInfo property)
    {
        return new Eina.Value(property.GetValue(source));
    }

    static internal void SetPropertyFromValue<T>(T target, PropertyInfo property, Eina.Value v)
    {
        property.SetValue(target, v.Unwrap());
    }

    /// <summary>Sets the properties of the <paramref name="child"/> from the properties of the given object
    /// <paramref name="o"/>.</summary>
    static internal void SetProperties<T>(T o, Efl.IModel child)
    {
        var properties = typeof(T).GetProperties();
        foreach (var prop in properties)
        {
            using (var tmp = ValueFromProperty(o, prop))
            {
                child.SetProperty(prop.Name, tmp);
            }
        }
    }

    /// <summary>Sets the properties of <paramref name="o"/> from the properties of <paramref name="child"/>.</summary>
    static internal void GetProperties<T>(T o, Efl.IModel child)
    {
        var properties = typeof(T).GetProperties();
        foreach (var prop in properties)
        {
            using (var v = child.GetProperty(prop.Name))
            {
                SetPropertyFromValue(o, prop, v);
            }
        }
    }
}

/// <summary>Helper class to simplify the creation of MVVM Models based on <see cref="Efl.IModel" />.
///
/// <para>This class enables usage of simple model classes to define the data to be stored in the native model
/// and presented in a friendly manner to the C# developer. Example:</para>
///
/// <code>
/// public class PersonModel
/// {
///     public string Name { get; set; }
///     public int Age { get; set; }
/// }
/// // Instantiating the model
/// var modelData = new Efl.UserModel&lt;PersonModel&gt;(parent);
/// modelData.Add(new PersonModel { Name = "John", Age = 30 };
/// var model = new Efl.GenericModel&lt;PersonModel&gt;(modelData, parent);
/// PersonModel p = await model.GetAtAsync(0);
/// </code>
/// </summary>
/// <typeparam name="T">The enclosed C# model class with the properties to be added to the native model.</typeparam>
[Efl.Eo.BindingEntity]
public class UserModel<T> : Efl.MonoModelInternal
{
   /// <summary>
   /// Creates a new root model.
   ///
   /// <para>The properties of <code>T</code> will be added to the underlying native model as properties the user can get/set on children
   /// of this model.</para>
   /// </summary>
   /// <param name="parent">The parent of the model.</param>
   public UserModel (Efl.Object parent = null) : base(Efl.MonoModelInternal.efl_mono_model_internal_class_get(), parent)
   {
     var properties = typeof(T).GetProperties();
     foreach (var prop in properties)
     {
        AddProperty(prop.Name, Eina.ValueTypeBridge.GetManaged(prop.PropertyType));
     }
   }

   /// <summary>Adds a new child to the model wrapping the properties of <c>o</c>
   ///
   /// <para>Reflection is used to instantiate a new <see cref="Efl.IModel" />-based class for this child and
   /// set the mirroring properties correctly.</para>
   /// </summary>
   ///
   /// <param name="o">The user model instance to be added to this model.</param>
   public void Add (T o)
   {
       Efl.IModel child = (Efl.IModel) this.AddChild();
       ModelHelper.SetProperties(o, child);
   }
}

#endif

}