最近研究了一段时间MMVM的数据绑定,目前得出的结论单向绑定就已经够使用了,目前有2种方法实现数据绑定。
方法1 使用一个类代替基础数据
如下代码所示,我使用int32来代替int 数据,这样就可以监听数据绑定了。由于C#并没有提供”=”符号的运算符重载,所以需要.value=xx 来触发数据变化事件,而其它计算,比较等都可使用运算符重载或隐式转换的方式。
int32 i32 = new int32(100);
//与各类型进行隐式转换
int ii = i32 + 100*2000;
float ff = i32;
double dd = i32;
//数据判断
if (i32 == 10) { }
if (i32 <= 10) { }
//监听数据变化
i32.valueChange += (change) => {
Debug.Log(change);
};
//最终设置数值
i32.value = 200;
Debug.Log(i32);
int32.cs核心代码
using System;
public struct int32 : IComparable, IFormattable, IComparable<int32>, IEquatable<int32>
{
private int m_Value;
public int value
{
get { return m_Value; }
set
{
if (m_Value != value)
{
m_Value = value;
valueChange?.Invoke(m_Value);
}
}
}
public Action<int> valueChange;
public int32(int value)
{
valueChange = null;
m_Value = value;
}
public static explicit operator byte(int32 value)
{
return (byte)value.value;
}
public static explicit operator sbyte(int32 value)
{
return (sbyte)value.value;
}
public static explicit operator short(int32 value)
{
return (short)value.value;
}
public static explicit operator ushort(int32 value)
{
return (ushort)value.value;
}
public static implicit operator int(int32 value)
{
return value.value;
}
public static explicit operator uint(int32 value)
{
return (uint)value.value;
}
public static implicit operator long(int32 value)
{
return value.value;
}
public static explicit operator ulong(int32 value)
{
return (ulong)value.value;
}
public static implicit operator float(int32 value)
{
return value.value;
}
public static implicit operator double(int32 value)
{
return value.value;
}
public static bool operator <(int32 lhs, int32 rhs)
{
return lhs.m_Value < rhs.m_Value;
}
public static bool operator <=(int32 lhs, int32 rhs)
{
return lhs.m_Value <= rhs.m_Value;
}
public static bool operator >(int32 lhs, int32 rhs)
{
return lhs.m_Value > rhs.m_Value;
}
public static bool operator >=(int32 lhs, int32 rhs)
{
return lhs.m_Value >= rhs.m_Value;
}
public int CompareTo(object obj)
{
return CompareTo(Convert.ToInt32(obj));
}
public override string ToString()
{
return m_Value.ToString();
}
public string ToString(string format)
{
return m_Value.ToString(format);
}
public string ToString(IFormatProvider provider)
{
return m_Value.ToString(provider);
}
public string ToString(string format, IFormatProvider provider)
{
return m_Value.ToString(format, provider);
}
public int CompareTo(int32 other)
{
if (m_Value == other.m_Value)
{
return 0;
}
else if (m_Value > other.m_Value)
{
return 1;
}
return -1;
}
public bool Equals(int32 other)
{
return m_Value == other.m_Value;
}
}
方法2 给基础数据起一个别名
利用nameof语法糖来代替别名,比如我们先有一个模块类。nameof语法糖会在编译的时候替换成字符串,所以它没有额外性能开销。
public class ViewMod
{
static ViewMod mod;
public static ViewMod Get()
{
if (mod == null)
mod = new ViewMod();
return mod;
}
public int m_Field;
public int field
{
get { return m_Field; }
set {
//修改数据抛出事件
m_Field = value;
Event.Dispatch(nameof(field), value);
}
}
}
监听模块类中数据被修改
var mod = ViewMod.Get();
//UI中监听变化
Event.AddListener(nameof(mod.field), (i) =>
{
Debug.Log("change: " + i);
});
//模块修改
mod.field = 200;
Event就比较简单了,注意这里还需要补充RemoveListener方法,如果要考虑其他short long float double这些数据可以拓展成泛型。
public class Event
{
public static Dictionary<string, Action<int>> events = new Dictionary<string, Action<int>>();
public static void Dispatch(string name, int value)
{
if (events.TryGetValue(name, out var action))
{
action?.Invoke(value);
}
}
public static void AddListener(string name, Action<int> action)
{
if (!events.TryGetValue(name, out var __))
{
events[name] = action;
}
else
{
events[name] += action;
}
}
}
我个人觉得方法2好一些。
1.nameof绑定了数据与事件,这样改了一个另外一个必须要改,不会出现漏改的情况。
2.需要考虑重名的问题,可以拓展nameof进行拼接。
3.需要考虑List中数据的问题,可以拓展nameof进行拼接。
欢迎一起讨论MMVM在实际项目中的应用。
- 本文固定链接: https://www.xuanyusong.com/archives/4790
- 转载请注明: 雨松MOMO于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

这个应该是MVVM数据绑定吧
MVVM的数据绑定以前前的uframe就做得还行了,就是效率差点
如果多个数据类 有相同名字的字段属性 是不是就不可以了
是的, 但是可以以模块类为基础获取类型做个拼接,一般同一个模块不会有两个相同字段属性,除非写了两个内部类,写两个一样的属性,但这种情况很少