2

Is it possible to use a simple action method - just like with Caliburn.Micro - instead of a command with MvvmCross bindings?

Example:

    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" />

It doesn't work out of the box, I tested that.

While I found a lot of samples about adding new target bindings, I didn't find a single one about adding a new source binding.

UPDATE:
This works now out of the box with the Rio binding. To use it, add the MvvmCross MethodBinding NuGet package to the Android project.

4

1 回答 1

3

到目前为止,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 存储库中的西藏绑定分支上已经发生了相当大的变化!)

于 2013-06-27T23:25:06.207 回答