MvvmCross和UIButton.Selected UISegmentedControl Bindings,iOS

时间:2013-08-29 09:08:30

标签: xamarin.ios xamarin mvvmcross

在使用MvvmCross框架构建的跨平台Xamarin应用程序中,我在Android .axml布局中使用了ToggleButton小部件。我使用以下绑定语法使用转换器将Checked属性绑定到View Model属性:

Checked MarketBuySellViewModel.Direction, Converter=DirectionBool, ConverterParameter='Sell'

一切都运作良好。在iOS端,看起来您可以使用Selected属性将UIButton用作ToggleButton。这意味着以下绑定应该实现我想要的iOS:

set.Bind (SellButton).For(b => b.Selected).To (vm => vm.MarketBuySellViewModel.Direction).WithConversion("DirectionBool", "Sell");

我在应用程序输出中没有遇到任何绑定错误,但绑定本身似乎不起作用。单击该按钮不会设置Direction属性,将方向设置为其他值不会在UIButton上设置Selected属性。

我是否需要创建自定义绑定,或者我只是错误地设置绑定?

我也尝试使用UISegmentedControl来达到同样的效果。在MvvmCross中是否支持绑定到此控件?我在源代码中没有看到任何对它的引用。这是否意味着我还需要为它创建自定义绑定?

2 个答案:

答案 0 :(得分:1)

对于UIButton,我不相信MvvmCross中包含的任何Selected绑定。因此 - 并且因为Selected没有简单的配对事件SelectedChanged,所以我认为Selected绑定应该单向工作(从ViewModel到View),但不是两个三通。

On UISwitch控件的Selected有绑定,而且我在这些情况下看到的控件使用最多。


如果您想为ValueChanged添加自定义双向绑定,那么我猜测您必须使用public class MvxUIButtonSelectedTargetBinding : MvxPropertyInfoTargetBinding<UIButton> { public MvxUIButtonSelectedTargetBinding(object target, PropertyInfo targetPropertyInfo) : base(target, targetPropertyInfo) { var view = View; view.ValueChanged += HandleValueChanged; } private void HandleValueChanged(object sender, System.EventArgs e) { var view = View; if (view == null) return; FireValueChanged(view.Selected); } public override MvxBindingMode DefaultMode { get { return MvxBindingMode.TwoWay; } } protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); if (isDisposing) { var view = View; if (view != null) { view.ValueChanged -= HandleValueChanged; } } } } 事件执行此操作(但是需要检查是否正确)。

为此,您只需构建一个目标绑定,例如:

protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)

这可以使用以下内容在registry.RegisterPropertyInfoBindingFactory(typeof(MvxUIButtonSelectedTargetBinding), typeof(UIButton), "Selected"); 中的安装程序中注册:

UISegmentedControl

同样地,我不相信任何人已经添加了双向UISegmentedControl绑定 - 但很高兴看到有人加入。

构建双向SelectedSegment绑定非常简单 - 您只需绑定到ValueChangedMySegmentedControl对 - 代码与上面类似。

或者,您可以切换到使用具有更好 Value`ValueChanged`对的自定义 public class MySegmentedControl : UISegmentedControl { // add more constructors if required public int Value { get { return base.SelectedSegment; } set { base.SelectedSegment = value; } } } ,该对将在没有自定义绑定的情况下自动工作 - 例如:

{{1}}

如果需要任何或所有这些自定义绑定,那么Mvx项目很乐意将这些绑定添加为问题或拉取请求以及https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs项目中的测试/演示UI

答案 1 :(得分:1)

可能对其他人有所帮助,所以我可以分享我的经验。我需要将UISegmentedControl.SelectedSegment属性双向绑定到ViewModel。单向绑定(ViewModel =&gt; View)默认工作。我无法正确利用Stuart提出的解决方案来继承UISegmentedControl。我试图确保链接器不会破坏新的自定义控制代码,但这对我没什么帮助。因此,一个完全可行的解决方案是使用MvxPropertyInfoTargetBinding的解决方案。这是适合我的代码:

public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
    public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
        : base(target, targetPropertyInfo)
    {
        this.View.ValueChanged += HandleValueChanged;
    }

    private void HandleValueChanged(object sender, System.EventArgs e)
    {
        var view = this.View;
        if (view == null)
        {
            return;
        }
        FireValueChanged(view.SelectedSegment);
    }

    public override MvxBindingMode DefaultMode
    {
        get { return MvxBindingMode.TwoWay; }
    }

    protected override void Dispose(bool isDisposing)
    {
        base.Dispose(isDisposing);
        if (isDisposing)
        {
            var view = this.View;
            if (view != null)
            {
                view.ValueChanged -= HandleValueChanged;
            }
        }
    }
}

public class Setup : MvxTouchSetup
{
    ...
    protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
    {
        registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
    }
}