return DynamicMetaObject.BindGetMember 的结果表达式应该怎么表示该成员不存在?

What should return the resulting expression of DynamicMetaObject.BindGetMember to express that the member does not exist?

我有这个(简化的)class,它通过 IDynamicMetaObjectProvider:

公开了动态成员
public abstract class MyDynViewModel: ViewModelBase, IDynamicMetaObjectProvider
{
    public DynamicMetaObject GetMetaObject(Expression parameter)
    {
        return new MyDynViewModelDynamicMetaObject(parameter, this);
    }

    public object GetDynamicObject(string name)
    {
        return GetChild(name) ?? GetCommand(name);
    }
}

这是我的(简化的)BindGetMember 方法:

public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
    var self = Expression.Convert(Expression, LimitType);
    Expression expression;
    var propertyName = binder.Name;
    var args = new Expression[1];

    args[0] = Expression.Constant(propertyName);
    expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);

    var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
    return getMember;
}

基本上GetChild(string)GetCommand(string)returnnull如果没有匹配名字的child/command

这里发生的是,如果我在 XAML 中绑定一个不存在的 child/command 名称,绑定将成功解析为 null 值。

但是,我想要的行为是绑定没有成功解析。原因是它允许我使用 PriorityBinding.

到目前为止,我得到了两个解决方案:

但是,none 这些解决方案会导致通常的绑定错误消息:

System.Windows.Data Warning: 40 : BindingExpression path error: '****' property not found on 'object' ''Object' (HashCode=13794971)'. BindingExpression:Path=****; DataItem='Object' (HashCode=13794971); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

那么,有没有 idea/advice 实现此行为的最佳方法?

据我所知,最接近的是:

System.Windows.Data Error: 17 : Cannot get 'EX' value (type 'Object') from '' (type 'Test'). BindingExpression:Path=EX; DataItem='Test' (HashCode=11280399); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') InvalidOperationException:'System.InvalidOperationException: Property path is not valid. 'System.Dynamic.DynamicObject+MetaDynamic' does not have a public property named 'Items'.

现在,棘手的问题是什么。我看到你有相当复杂的代码,那是因为你正在从零开始创建一切。你有没有考虑过这个:

public class TestViewModel : DynamicObject
{
   public override bool TryGetMember(GetMemberBinder binder, out object result)
   {
       result = null;
       return false; // if we didn't find member.

   }
}

代替?

如果这不符合您的需要,首先,您需要修改您的 GetDynamicObject 签名,添加一个额外的参数 "result"。

您需要在 Expression 中包装功能,伪代码:

public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
    var self = Expression.Convert(Expression, LimitType);
    Expression expression;
    var propertyName = binder.Name;
    var args = new Expression[1];

    args[0] = Expression.Constant(propertyName);
    expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);

    expression = "if GetDynamicObject returned false, means we found nothing.
          then we should return binder.FallbackGetMember(this, e)";

    var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
    return getMember;
}

您可以检查 PropertyPath.cs DLR 实现并跟踪它:

// Define other methods and classes here
// 6. IDynamicMetaObjectProvider
// This supports the DLR's dynamic objects
if (accessor == null && 
    SystemCoreHelper.IsIDynamicMetaObjectProvider(item))
{
    accessor = SystemCoreHelper.NewDynamicPropertyAccessor(
                    item.GetType(), propertyName);
}