是否可以使用简单的操作方法(就像使用 Caliburn.Micro 一样)而不是使用 MvvmCross 绑定(bind)的命令?
示例:
public void Action()
{
Tip = 11;
}
<Button
android:text="Button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/button1"
local:MvxBind="Click Action" />
它不能开箱即用,我测试过。
虽然我找到了很多关于添加新目标绑定(bind)的示例,但我没有找到任何关于添加新源绑定(bind)的示例。
更新:
现在,它可以与 Rio 绑定(bind)一起开箱即用。要使用它,请将 MvvmCross MethodBinding NuGet 包添加到 Android 项目中。
最佳答案
到目前为止,MvvmCross 的重点一直是允许多平台目标绑定(bind),而源代码仍然主要是“普通”INotifyPropertyChanged
。
ViewModel 结构存在一些偏差 - 例如:
MvxCommandCollection
- http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html- 一些用户使用 Fody - http://twincoders.com/blog/codigo-limpio-con-fody/
最近,该区域还记录了几个新功能请求:
- 自动命令 - 我想这就是您在这里问的问题 - https://github.com/slodge/MvvmCross/issues/301
- Rio 绑定(bind)源 - https://github.com/slodge/MvvmCross/issues/299
- 西藏绑定(bind) - https://github.com/slodge/MvvmCross/issues/298
因此,我确实希望将来在该领域会公开更多功能......
话虽如此,如果您今天想让它正常工作,那么 MvvmCross Binding 是可重写的,因此您可以相当轻松地做到这一点:
1. 实现一个使用反射调用 MethodInfo 的ICommand
(为了完整起见,这可能还应该使用一个参数(如果可用)) - 某种 InvokeMethodCommand
(此代码留给读者!)
.
2. 实现一个包装InvokeMethodCommand
的 MyMethodSourceBinding
类 - 类似于:
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. 在您自己的自定义绑定(bind)构建器中提供此源绑定(bind)工厂 - 例如:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. 在设置期间提供此绑定(bind)构建器
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
注意:这种方法目前仅适用于高级用户...正如本问题第一部分中所建议的那样,我确实预计该区域的代码会发生很大变化,因此您可能还会遇到维护 fork 的一些问题在这个区域。 (事实上,在 GitHub 存储库的西藏绑定(bind)分支上,这方面的代码已经发生了相当大的变化!)
关于mvvmcross - 绑定(bind)到操作方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17351375/