到目前为止,MvvmCross 的大部分重点都放在允许多平台目标绑定上,而源代码仍然主要是 'vanilla' INotifyPropertyChanged
。
在 ViewModel 结构方面存在一些偏差 - 例如:
最近,该区域还记录了几个新功能请求:
正因为如此,我确实希望将来会在该领域公开更多功能......
话虽如此,如果你想今天让它工作,那么 MvvmCross Binding 是可覆盖的,所以你可以很容易地做到这一点:
1. 实现一个
ICommand
使用反射调用 MethodInfo 的方法(为了完整起见,如果可用,这也应该使用参数) - 某种
InvokeMethodCommand
(代码留给读者!)
.
2.实现一个
MyMethodSourceBinding
包装类
InvokeMethodCommand
- 类似:
public class MyMethodSourceBinding : MvxSourceBinding
{
private readonly MethodInfo _methodInfo;
protected MyMethodSourceBinding(object source, MethodInfo methodInfo)
: base(source)
{
_methodInfo = _methodInfo;
}
public override void SetValue(object value)
{
// do nothing - not allowed
}
public override Type SourceType
{
get { return typeof(ICommand); }
}
public override bool TryGetValue(out object value)
{
value = new InvokeMethodCommand(source, _methodInfo);
return true;
}
}
3. 用您自己的实现覆盖 MvvmCross 的注册
IMvxSourceBindingFactory
,该实现可以检测方法何时存在 - 遗憾的是,今天大部分是剪切和粘贴编码 - 它类似于
public class MySourceBindingFactory
: IMvxSourceBindingFactory
{
private IMvxSourcePropertyPathParser _propertyPathParser;
private IMvxSourcePropertyPathParser SourcePropertyPathParser
{
get
{
if (_propertyPathParser == null)
{
_propertyPathParser = Mvx.Resolve<IMvxSourcePropertyPathParser>();
}
return _propertyPathParser;
}
}
public IMvxSourceBinding CreateBinding(object source, string combinedPropertyName)
{
var tokens = SourcePropertyPathParser.Parse(combinedPropertyName);
return CreateBinding(source, tokens);
}
public IMvxSourceBinding CreateBinding(object source, IList<MvxPropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}
var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxPropertyToken propertyToken,
List<MvxPropertyToken> remainingTokens)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}
throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}
private static IMvxSourceBinding CreateLeafBinding(object source, MvxPropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
//**************************
// Special code is here
var propertyToken = (MvxPropertyNamePropertyToken) propertyToken;
if (source != null)
{
var method = source.GetType().GetMethod(propertyToken.PropertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
return new MyMethodSourceBinding(source, method);
}
}
return new MvxSimpleLeafPropertyInfoSourceBinding(source,
(MvxPropertyNamePropertyToken) propertyToken);
// Special code ends here
//**************************
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}
throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}
}
4. 在您自己的自定义绑定构建器中提供此源绑定工厂 - 例如:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. 在设置期间提供此绑定生成器
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
注意:此方法目前仅适用于高级用户...正如本问题第一部分中所建议的,我确实希望该区域的代码会发生很大变化,因此您可能还会遇到一些维护该区域分支的问题. (事实上,这方面的代码在 GitHub 存储库中的西藏绑定分支上已经发生了相当大的变化!)