优化ui绑定侧逻辑
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace XericUI.ReflectionUIGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 绑定名称前缀树(Trie),支持通过完整路径或成员名后缀快速查找 AvrgMvvmBinding。
|
||||
///
|
||||
/// 使用场景:
|
||||
/// - Find("XericUI.MyData.speed") → 完整路径精确命中
|
||||
/// - FindByMemberName("speed") → 沿 Trie 叶节点查找末段匹配
|
||||
///
|
||||
/// 在 BuildMDVM 时构建,绑定到 AvrgMvvmBindingCollection。
|
||||
/// </summary>
|
||||
internal class AvrgBindingTrie
|
||||
{
|
||||
private class Node
|
||||
{
|
||||
public AvrgMvvmBinding Binding;
|
||||
public readonly Dictionary<string, Node> Children = new();
|
||||
}
|
||||
|
||||
private readonly Node _root = new();
|
||||
private readonly Dictionary<string, AvrgMvvmBinding> _memberNameIndex = new();
|
||||
|
||||
public void Insert(string fullPath, AvrgMvvmBinding binding)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullPath) || binding == null) return;
|
||||
|
||||
var parts = fullPath.Split('.');
|
||||
var current = _root;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (!current.Children.TryGetValue(part, out var child))
|
||||
{
|
||||
child = new Node();
|
||||
current.Children[part] = child;
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
current.Binding = binding;
|
||||
|
||||
// 同时建成员名索引(末段)
|
||||
string memberName = parts[parts.Length - 1];
|
||||
if (!_memberNameIndex.ContainsKey(memberName))
|
||||
_memberNameIndex[memberName] = binding;
|
||||
}
|
||||
|
||||
/// <summary>通过完整路径精确查找(如 "XericUI.MyData.speed")</summary>
|
||||
public AvrgMvvmBinding Find(string fullPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullPath)) return null;
|
||||
|
||||
var parts = fullPath.Split('.');
|
||||
var current = _root;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (!current.Children.TryGetValue(part, out current))
|
||||
return null;
|
||||
}
|
||||
return current?.Binding;
|
||||
}
|
||||
|
||||
/// <summary>通过成员名查找(如 "speed")— O(1) 直接索引</summary>
|
||||
public AvrgMvvmBinding FindByMemberName(string memberName)
|
||||
{
|
||||
_memberNameIndex.TryGetValue(memberName, out var binding);
|
||||
return binding;
|
||||
}
|
||||
|
||||
/// <summary>清除所有索引</summary>
|
||||
public void Clear()
|
||||
{
|
||||
_root.Children.Clear();
|
||||
_memberNameIndex.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,12 @@ namespace XericUI.ReflectionUIGenerator
|
||||
bindingCollection.SourceMetaDataSet = this;
|
||||
var scheduler = new AvrgMvvmScheduler(resolverConfig);
|
||||
|
||||
// ★ 构建前缀树索引
|
||||
var trie = new AvrgBindingTrie();
|
||||
string typePrefix = businessTarget != null
|
||||
? businessTarget.GetType().FullName + "."
|
||||
: "";
|
||||
|
||||
foreach (var metaData in _metaDataList)
|
||||
{
|
||||
if (metaData.AccessorFactory == null) continue;
|
||||
@@ -137,9 +143,14 @@ namespace XericUI.ReflectionUIGenerator
|
||||
string subPath = subMetaData.PropertyPath;
|
||||
if (string.IsNullOrEmpty(subPath)) continue;
|
||||
|
||||
// 创建子属性访问器
|
||||
var subAccessor = new AvrgSubPropertyAccessor(
|
||||
accessor, subPath, subMetaData);
|
||||
|
||||
var subBinding = new AvrgMvvmBinding
|
||||
{
|
||||
MetaData = subMetaData,
|
||||
Accessor = subAccessor,
|
||||
ReadFunc = () => ReadSubProperty(accessor.GetValue(), subPath),
|
||||
WriteAction = (val) =>
|
||||
{
|
||||
@@ -157,8 +168,13 @@ namespace XericUI.ReflectionUIGenerator
|
||||
// 注册到调度器
|
||||
scheduler.Register(binding);
|
||||
bindingCollection.Add(binding);
|
||||
|
||||
// ★ 插入前缀树(完整路径: Type.FullName.MemberName)
|
||||
string fullPath = typePrefix + metaData.MemberName;
|
||||
trie.Insert(fullPath, binding);
|
||||
}
|
||||
|
||||
bindingCollection.SetTrie(trie);
|
||||
bindingCollection.AttachScheduler(scheduler);
|
||||
return bindingCollection;
|
||||
}
|
||||
|
||||
@@ -45,21 +45,75 @@ namespace XericUI.ReflectionUIGenerator
|
||||
/// <summary>数据侧写入的缓存值</summary>
|
||||
public object DataCachedValue { get; set; }
|
||||
|
||||
// ============ 验证状态 ============
|
||||
|
||||
private ValidationState _validationState = ValidationState.Normal;
|
||||
|
||||
/// <summary>当前验证状态</summary>
|
||||
public ValidationState CurrentValidationState => _validationState;
|
||||
|
||||
/// <summary>验证状态变更事件 — UI 组件订阅以切换样式</summary>
|
||||
public event Action<ValidationState> OnValidationStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 校验值是否满足元数据约束
|
||||
/// 返回:Normal(通过)、Warning(放行但警告)、Invalid(驳回)
|
||||
/// </summary>
|
||||
public ValidationState ValidateValue(object value)
|
||||
{
|
||||
if (MetaData == null) return ValidationState.Normal;
|
||||
|
||||
// 1. 空值检查(Required)
|
||||
if (MetaData.Required && (value == null || (value is string s && string.IsNullOrEmpty(s))))
|
||||
return ValidationState.Invalid;
|
||||
|
||||
// 2. 范围检查(RangeMin/RangeMax)
|
||||
if (value is IConvertible)
|
||||
{
|
||||
float num = Convert.ToSingle(value);
|
||||
|
||||
if (MetaData.RangeMin.HasValue && num < MetaData.RangeMin.Value)
|
||||
return ValidationState.Invalid;
|
||||
|
||||
if (MetaData.RangeMax.HasValue && num > MetaData.RangeMax.Value)
|
||||
return ValidationState.Invalid;
|
||||
}
|
||||
|
||||
return ValidationState.Normal;
|
||||
}
|
||||
|
||||
/// <summary>更新验证状态并触发回调(仅状态变化时触发)</summary>
|
||||
internal void SetValidationState(ValidationState newState)
|
||||
{
|
||||
if (_validationState != newState)
|
||||
{
|
||||
_validationState = newState;
|
||||
OnValidationStateChanged?.Invoke(_validationState);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>重置验证状态为 Normal(不触发事件)</summary>
|
||||
internal void ResetValidationState()
|
||||
{
|
||||
_validationState = ValidationState.Normal;
|
||||
}
|
||||
|
||||
// ============ UI 绑定 ============
|
||||
|
||||
/// <summary>UI 值变更回调委托 — UI 组件订阅此回调以更新显示</summary>
|
||||
public Action<object> OnUIDataChanged;
|
||||
/// <summary>UI 值变更回调委托 — UI 组件订阅此回调以更新显示(附带验证状态)</summary>
|
||||
public Action<object, ValidationState> OnUIDataChanged;
|
||||
|
||||
/// <summary>通知 UI 更新值</summary>
|
||||
public void NotifyUIUpdate(object value)
|
||||
/// <summary>通知 UI 更新值(带验证状态)</summary>
|
||||
public void NotifyUIUpdate(object value, ValidationState state)
|
||||
{
|
||||
OnUIDataChanged?.Invoke(value);
|
||||
OnUIDataChanged?.Invoke(value, state);
|
||||
}
|
||||
|
||||
/// <summary>清除所有 UI 变更订阅</summary>
|
||||
public void ClearUIEvent()
|
||||
{
|
||||
OnUIDataChanged = null;
|
||||
OnValidationStateChanged = null;
|
||||
}
|
||||
|
||||
// ============ 便捷方法 ============
|
||||
|
||||
@@ -4,12 +4,13 @@ using System.Collections.Generic;
|
||||
namespace XericUI.ReflectionUIGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 绑定集合 — 统一管理所有 AvrgMvvmBinding
|
||||
/// 绑定集合 — 统一管理所有 AvrgMvvmBinding,提供字符串索引器和前缀树快速查找
|
||||
/// </summary>
|
||||
public class AvrgMvvmBindingCollection : IEnumerable<AvrgMvvmBinding>
|
||||
{
|
||||
private List<AvrgMvvmBinding> _bindings = new List<AvrgMvvmBinding>();
|
||||
private AvrgMvvmScheduler _scheduler;
|
||||
private AvrgBindingTrie _trie;
|
||||
|
||||
/// <summary>
|
||||
/// 绑定的元数据集引用(可选)
|
||||
@@ -21,6 +22,11 @@ namespace XericUI.ReflectionUIGenerator
|
||||
/// </summary>
|
||||
public int Count => _bindings.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 调度器引用(在 BuildMDVM 时设置)
|
||||
/// </summary>
|
||||
public AvrgMvvmScheduler Scheduler => _scheduler;
|
||||
|
||||
/// <summary>
|
||||
/// 添加绑定
|
||||
/// </summary>
|
||||
@@ -29,16 +35,53 @@ namespace XericUI.ReflectionUIGenerator
|
||||
_bindings.Add(binding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置前缀树索引(由 BuildMDVM 构建后注入)
|
||||
/// </summary>
|
||||
internal void SetTrie(AvrgBindingTrie trie)
|
||||
{
|
||||
_trie = trie;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定索引的绑定
|
||||
/// </summary>
|
||||
public AvrgMvvmBinding this[int index] => _bindings[index];
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定成员名称的绑定
|
||||
/// 通过成员名访问绑定(如 bindingCollection["speed"])
|
||||
/// get: 从数据源读取当前值
|
||||
/// set: 走完整的 MVVM 管线:WriteFromData → MarkDataDirty → Flush → UI 同步
|
||||
/// </summary>
|
||||
public object this[string memberName]
|
||||
{
|
||||
get
|
||||
{
|
||||
var binding = FindByMemberName(memberName);
|
||||
return binding?.ReadFromDataSource();
|
||||
}
|
||||
set
|
||||
{
|
||||
var binding = FindByMemberName(memberName);
|
||||
if (binding != null && _scheduler != null)
|
||||
{
|
||||
binding.WriteFromData(value);
|
||||
_scheduler.MarkDataDirty(binding);
|
||||
_scheduler.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定成员名称的绑定(优先查 Trie,回退线性查找)
|
||||
/// </summary>
|
||||
public AvrgMvvmBinding FindByMemberName(string memberName)
|
||||
{
|
||||
if (_trie != null)
|
||||
{
|
||||
var found = _trie.Find(memberName) ?? _trie.FindByMemberName(memberName);
|
||||
if (found != null) return found;
|
||||
}
|
||||
return _bindings.Find(b => b.MetaData?.MemberName == memberName);
|
||||
}
|
||||
|
||||
@@ -72,6 +115,7 @@ namespace XericUI.ReflectionUIGenerator
|
||||
public void Clear()
|
||||
{
|
||||
_bindings.Clear();
|
||||
_trie?.Clear();
|
||||
_scheduler?.Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,11 @@ namespace XericUI.ReflectionUIGenerator
|
||||
///
|
||||
/// 冲突解决策略:
|
||||
/// - 仅数据脏 → 通知 UI 更新
|
||||
/// - 仅 UI 脏 → 写入数据源
|
||||
/// - 仅 UI 脏 → 写入数据源(写入前校验,Invalid 驳回)
|
||||
/// - 双方都脏 → 走配置的冲突解决策略
|
||||
///
|
||||
/// 验证拦截:在 CommitToDataSource 前通过 Binding.ValidateValue() 校验。
|
||||
/// Invalid 值被驳回不写入,仅通知 UI 进入无效状态。
|
||||
/// </summary>
|
||||
public class AvrgMvvmScheduler
|
||||
{
|
||||
@@ -79,20 +82,36 @@ namespace XericUI.ReflectionUIGenerator
|
||||
|
||||
if (uiDirty && dataDirty)
|
||||
{
|
||||
// 双方都脏 — 走冲突解决
|
||||
// 双方都脏 — 走冲突解决(内部含验证)
|
||||
ResolveConflict(binding);
|
||||
}
|
||||
else if (dataDirty)
|
||||
{
|
||||
// 仅数据侧更新 → 通知 UI
|
||||
// 仅数据侧更新 → 验证后通知 UI
|
||||
var value = binding.DataCachedValue ?? binding.ReadFromDataSource();
|
||||
var state = binding.ValidateValue(value);
|
||||
binding.SetValidationState(state);
|
||||
|
||||
binding.CommitToDataSource(value);
|
||||
binding.NotifyUIUpdate(value);
|
||||
binding.NotifyUIUpdate(value, state);
|
||||
}
|
||||
else if (uiDirty)
|
||||
{
|
||||
// 仅 UI 侧更新 → 写入数据源
|
||||
binding.CommitToDataSource(binding.UICachedValue);
|
||||
// 仅 UI 侧更新 → 验证后写入数据源
|
||||
var value = binding.UICachedValue;
|
||||
var state = binding.ValidateValue(value);
|
||||
|
||||
if (state == ValidationState.Invalid)
|
||||
{
|
||||
// ★ 无效值:驳回不写入,仅通知 UI 进入无效态
|
||||
binding.SetValidationState(state);
|
||||
binding.NotifyUIUpdate(value, state);
|
||||
return;
|
||||
}
|
||||
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(value);
|
||||
// UI 是发起方,不再通知自身(但验证状态变更需通知)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,8 +125,10 @@ namespace XericUI.ReflectionUIGenerator
|
||||
var resolvedValue = OnConflictDetected.Invoke(binding, DefaultStrategy);
|
||||
if (resolvedValue != null)
|
||||
{
|
||||
var state = binding.ValidateValue(resolvedValue);
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(resolvedValue);
|
||||
binding.NotifyUIUpdate(resolvedValue);
|
||||
binding.NotifyUIUpdate(resolvedValue, state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -120,8 +141,10 @@ namespace XericUI.ReflectionUIGenerator
|
||||
// 2. 检查 ResolverConfig 中的自定义策略
|
||||
if (_resolverConfig != null && _resolverConfig.TryResolve(binding, out object configResolvedValue))
|
||||
{
|
||||
var state = binding.ValidateValue(configResolvedValue);
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(configResolvedValue);
|
||||
binding.NotifyUIUpdate(configResolvedValue);
|
||||
binding.NotifyUIUpdate(configResolvedValue, state);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -129,38 +152,70 @@ namespace XericUI.ReflectionUIGenerator
|
||||
switch (DefaultStrategy)
|
||||
{
|
||||
case ConflictResolutionStrategy.PreferUI:
|
||||
binding.CommitToDataSource(binding.UICachedValue);
|
||||
binding.NotifyUIUpdate(binding.UICachedValue);
|
||||
break;
|
||||
|
||||
case ConflictResolutionStrategy.PreferData:
|
||||
var dataValue = binding.DataCachedValue ?? binding.ReadFromDataSource();
|
||||
binding.CommitToDataSource(dataValue);
|
||||
binding.NotifyUIUpdate(dataValue);
|
||||
break;
|
||||
|
||||
case ConflictResolutionStrategy.CompareValues:
|
||||
// 比较UI值和数据值
|
||||
object uiVal = binding.UICachedValue;
|
||||
object dataVal = binding.DataCachedValue ?? binding.ReadFromDataSource();
|
||||
|
||||
if (Equals(uiVal, dataVal))
|
||||
{
|
||||
// 值相同,忽略冲突
|
||||
binding.NotifyUIUpdate(dataVal);
|
||||
var val = binding.UICachedValue;
|
||||
var state = binding.ValidateValue(val);
|
||||
if (state == ValidationState.Invalid)
|
||||
{
|
||||
binding.SetValidationState(state);
|
||||
binding.NotifyUIUpdate(val, state);
|
||||
return;
|
||||
}
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(val);
|
||||
binding.NotifyUIUpdate(val, state);
|
||||
break;
|
||||
}
|
||||
|
||||
// 值不同,回退到 PreferUI
|
||||
binding.CommitToDataSource(binding.UICachedValue);
|
||||
binding.NotifyUIUpdate(binding.UICachedValue);
|
||||
Debug.LogWarning($"[AvrgMvvmScheduler] 值冲突(CompareValues回退PreferUI): {binding.MetaData?.MemberName}");
|
||||
break;
|
||||
case ConflictResolutionStrategy.PreferData:
|
||||
{
|
||||
var dataValue = binding.DataCachedValue ?? binding.ReadFromDataSource();
|
||||
var state = binding.ValidateValue(dataValue);
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(dataValue);
|
||||
binding.NotifyUIUpdate(dataValue, state);
|
||||
break;
|
||||
}
|
||||
|
||||
case ConflictResolutionStrategy.CompareValues:
|
||||
{
|
||||
object uiVal = binding.UICachedValue;
|
||||
object dataVal = binding.DataCachedValue ?? binding.ReadFromDataSource();
|
||||
|
||||
if (Equals(uiVal, dataVal))
|
||||
{
|
||||
// 值相同,忽略冲突
|
||||
var state2 = binding.ValidateValue(dataVal);
|
||||
binding.SetValidationState(state2);
|
||||
binding.NotifyUIUpdate(dataVal, state2);
|
||||
break;
|
||||
}
|
||||
|
||||
// 值不同,回退到 PreferUI
|
||||
var val = binding.UICachedValue;
|
||||
var state = binding.ValidateValue(val);
|
||||
if (state == ValidationState.Invalid)
|
||||
{
|
||||
binding.SetValidationState(state);
|
||||
binding.NotifyUIUpdate(val, state);
|
||||
return;
|
||||
}
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(val);
|
||||
binding.NotifyUIUpdate(val, state);
|
||||
Debug.LogWarning($"[AvrgMvvmScheduler] 值冲突(CompareValues回退PreferUI): {binding.MetaData?.MemberName}");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
binding.CommitToDataSource(binding.UICachedValue);
|
||||
binding.NotifyUIUpdate(binding.UICachedValue);
|
||||
break;
|
||||
{
|
||||
var val = binding.UICachedValue;
|
||||
var state = binding.ValidateValue(val);
|
||||
binding.SetValidationState(state);
|
||||
binding.CommitToDataSource(val);
|
||||
binding.NotifyUIUpdate(val, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace XericUI.ReflectionUIGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 子属性值访问器 — 通过父访问器 + PropertyPath 访问结构的子字段
|
||||
///
|
||||
/// 用于拆分属性([XuiavrgSplit])场景,如 Vector3 的 x/y/z 分量。
|
||||
/// GetValue 通过反射读取父值的子字段/属性;SetValue 由绑定层的 WriteAction 处理。
|
||||
/// </summary>
|
||||
internal class AvrgSubPropertyAccessor : IAvrgValueAccessor
|
||||
{
|
||||
private readonly IAvrgValueAccessor _parentAccessor;
|
||||
private readonly string _propertyPath;
|
||||
private readonly AvrgMemberMetaData _metaData;
|
||||
|
||||
public AvrgSubPropertyAccessor(
|
||||
IAvrgValueAccessor parentAccessor,
|
||||
string propertyPath,
|
||||
AvrgMemberMetaData metaData)
|
||||
{
|
||||
_parentAccessor = parentAccessor ?? throw new ArgumentNullException(nameof(parentAccessor));
|
||||
_propertyPath = propertyPath ?? throw new ArgumentNullException(nameof(propertyPath));
|
||||
_metaData = metaData;
|
||||
}
|
||||
|
||||
public Type ValueType => _metaData?.ValueType ?? typeof(float);
|
||||
|
||||
public bool IsReadOnly => _parentAccessor.IsReadOnly;
|
||||
|
||||
public object GetValue()
|
||||
{
|
||||
var parentValue = _parentAccessor.GetValue();
|
||||
if (parentValue == null || string.IsNullOrEmpty(_propertyPath))
|
||||
return null;
|
||||
|
||||
var type = parentValue.GetType();
|
||||
var field = type.GetRuntimeField(_propertyPath);
|
||||
if (field != null) return field.GetValue(parentValue);
|
||||
|
||||
var prop = type.GetRuntimeProperty(_propertyPath);
|
||||
return prop?.GetValue(parentValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 子属性设置由绑定层的 WriteAction 统一处理(ReadSubProperty/WriteSubProperty),
|
||||
/// 此方法不应被直接调用。
|
||||
/// </summary>
|
||||
public void SetValue(object value)
|
||||
{
|
||||
var parentValue = _parentAccessor.GetValue();
|
||||
if (parentValue == null) return;
|
||||
|
||||
var type = parentValue.GetType();
|
||||
var field = type.GetRuntimeField(_propertyPath);
|
||||
if (field != null)
|
||||
{
|
||||
field.SetValue(parentValue, value);
|
||||
_parentAccessor.SetValue(parentValue);
|
||||
return;
|
||||
}
|
||||
|
||||
var prop = type.GetRuntimeProperty(_propertyPath);
|
||||
if (prop != null && prop.CanWrite)
|
||||
{
|
||||
prop.SetValue(parentValue, value);
|
||||
_parentAccessor.SetValue(parentValue);
|
||||
}
|
||||
}
|
||||
|
||||
public string FormatDisplay(object value)
|
||||
{
|
||||
if (_metaData?.FormatText != null && value is IFormattable formattable)
|
||||
return formattable.ToString(_metaData.FormatText, null);
|
||||
return value?.ToString() ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace XericUI.ReflectionUIGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 值校验状态枚举
|
||||
/// Normal = 正常(通过校验),Warning = 警告(值在警告范围但放行),Invalid = 无效(值被驳回不写入)
|
||||
/// </summary>
|
||||
public enum ValidationState
|
||||
{
|
||||
Normal = 0,
|
||||
Warning = 1,
|
||||
Invalid = 2
|
||||
}
|
||||
}
|
||||
@@ -308,14 +308,14 @@ namespace XericUI.ReflectionUIGenerator
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
var value = binding.ReadFromDataSource();
|
||||
binding.NotifyUIUpdate(value);
|
||||
binding.NotifyUIUpdate(value, ValidationState.Normal);
|
||||
|
||||
if (binding.SubBindings?.Count > 0)
|
||||
{
|
||||
foreach (var subBinding in binding.SubBindings)
|
||||
{
|
||||
var subValue = subBinding.ReadFromDataSource();
|
||||
subBinding.NotifyUIUpdate(subValue);
|
||||
subBinding.NotifyUIUpdate(subValue, ValidationState.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,16 +127,17 @@ namespace XericUI.ReflectionUIGenerator
|
||||
|
||||
if (bindingCollection != null)
|
||||
{
|
||||
var matchedBindings = bindingCollection.FindByMemberName(metaData.MemberName);
|
||||
if (matchedBindings != null)
|
||||
var scheduler = bindingCollection.Scheduler;
|
||||
var matchedBinding = bindingCollection.FindByMemberName(metaData.MemberName);
|
||||
if (matchedBinding != null)
|
||||
{
|
||||
entry.AddBinding(matchedBindings, null);
|
||||
entry.AddBinding(matchedBinding, scheduler);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var binding in bindingCollection)
|
||||
{
|
||||
entry.AddBinding(binding, null);
|
||||
entry.AddBinding(binding, scheduler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -156,13 +157,14 @@ namespace XericUI.ReflectionUIGenerator
|
||||
|
||||
if (CurrentEntries != null && bindingCollection != null)
|
||||
{
|
||||
var scheduler = bindingCollection.Scheduler;
|
||||
foreach (var entry in CurrentEntries)
|
||||
{
|
||||
if (entry is XuiFieldTempEntry tempEntry)
|
||||
{
|
||||
var matched = bindingCollection.FindByMemberName(entry.EntryName);
|
||||
if (matched != null)
|
||||
tempEntry.AddBinding(matched, null);
|
||||
tempEntry.AddBinding(matched, scheduler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,5 +459,7 @@ namespace XericUI.ReflectionUIGenerator
|
||||
|
||||
_leafGroupMap.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user