自定义类型的MvvmCross绑定属性到自定义视图

时间:2015-07-02 05:16:43

标签: mvvm binding viewmodel mvvmcross custom-view

我尝试使用自定义View在View Model中绑定自定义类型的属性,但是在Binder方法" SetValue(对象值)" value始终为null。为什么会这样?自定义类型的绑定属性是否与MvvmCross中的自定义视图不可能?

我的ViewModel:

public class RecipesFiltersVM : MvxViewModel
{
    public SearchField DishField { get; private set; }
    public SearchField CuisineField { get; private set; }
    public SearchField IngredientField { get; private set; }

    private readonly IFiltersService _filtersService;

    public RecipesFiltersVM(IFiltersService filtersService)
    {
        _filtersService = filtersService;

        UpdateSearchFields ();
    }

    private async void UpdateSearchFields ()
    {
        var allFilters = await _filtersService.LoadAllFilters ();

        DishField = new SearchField (
            allFilters
            .Where(f => f.Type == FilterType.Dish)
            .ToList()
        );
        CuisineField = new SearchField (
            allFilters
            .Where(f => f.Type == FilterType.Cuisine)
            .ToList()
        );
        IngredientField = new SearchField (
            allFilters
            .Where(f => f.Type == FilterType.Ingredient)
            .ToList()
        );
    }
}

我的搜索字段:

public class SearchField : MvxViewModel
{
    private String _searchResult;
    public String SearchResult {
        get { return _searchResult; }
        set {
            _searchResult = value;
            RaisePropertyChanged (() => SearchResult);
            UpdateFoundFilters ();
        }
    }

    private ObservableCollection<Filter> _foundFilters;
    public ObservableCollection<Filter> FoundFilters {
        get { return _foundFilters; }
        set {
            _foundFilters = value;
            RaisePropertyChanged (() => FoundFilters);
        }
    }
}

在CustomView中:

public class SearchFieldView : UIView
{
    public UITextField SearchResult { get { return _searchResult; } }
    private UITextField _searchResult;

    public UITableView FoundFilters { get { return _foundFilters; } }
    private UITableView _foundFilters;
}

在宾德:

public class SearchFieldViewWithSearchFieldBinder : MvxTargetBinding
{
    protected SearchFieldView SearchFieldView {
        get { return (SearchFieldView)Target; }
    }

    public SearchFieldViewWithSearchFieldBinder (SearchFieldView target)
        : base (target)
    {

    }

    public override void SetValue (object value)
    {
        //value is always null!
    }

    public override Type TargetType {
        get
        {
            return typeof(SearchField);
        }
    }

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

设定:

protected override void FillTargetFactories (Cirrious.MvvmCross.Binding.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
    {
        registry.RegisterCustomBindingFactory<SearchFieldView> (
            "SearchField",
            indicators => new SearchFieldViewWithSearchFieldBinder(indicators)
        );
        base.FillTargetFactories (registry);
    }

在ViewController中:

var set = this.CreateBindingSet<RecipesFiltersDialog, RecipesFiltersVM>();
set.Bind (_dish).For("SearchField").To (vm => vm.DishField);
set.Bind (_cuisine).For("SearchField").To (vm => vm.CuisineField);
set.Bind (_ingredient).For("SearchField").To (vm => vm.IngredientField);
set.Apply ();

UPD

解决了两种更新ViewModel代码的方法。首先,我更改了自定义属性声明,如:

private SearchField _dishField;
    public SearchField DishField {
        get
        {
            return _dishField;
        }
        set
        {
            _dishField = value;
            RaisePropertyChanged (() => DishField);
        }
    }

其次我在UpdateSearchFields()执行之前在ViewModel构造函数中初始化我的属性:

public RecipesFiltersVM(IFiltersService filtersService)
    {
        _filtersService = filtersService;

        DishField = new SearchField (new List<Filter> ());
        CuisineField = new SearchField (new List<Filter> ());
        IngredientField = new SearchField (new List<Filter> ());

        UpdateSearchFields ();
    }

2 个答案:

答案 0 :(得分:0)

您需要为自定义视图创建自己的自定义绑定。例如,如果您遵循正常的MvvmCross使用公共C#属性和C#事件来定义自定义视图中的项目,那么您应该可以执行以下操作:

public class SearchFieldView : UIView, IMvxBindable
{
    public IMvxBindingContext BindingContext { get; set; }

    public SearchFieldView()
    {
         this.CreateBindingContext();
    }

    public UITextField SearchResult { get { return _searchResult; } }
    private UITextField _searchResult;

    public UITableView FoundFilters { get { return _foundFilters; } }
    private UITableView _foundFilters;

    [MvxSetToNullAfterBinding]
    public object DataContext
    {
        get { return BindingContext.DataContext; }
        set { BindingContext.DataContext = value; }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            BindingContext.ClearAllBindings();
        }
        base.Dispose(disposing);
    }
}

然后它应该“工作”。用于灵感结帐的内容,例如MvxViewMvxTableViewCell

或者你也可以通过实现类似MvxUISegmentedControlSelectedSegmentTargetBinding的方式来做你自己的MvxPropertyInfoTargetBinding,就像MvvmCross如何处理UISegmentedControlBindings一样。

答案 1 :(得分:0)

以两种方式解决Stuart's评论更新ViewModel代码。首先,我更改了自定义属性声明,如:

struct Grade{
   string id;
   int score;
}; 

bool operator<(Grade const& lhs, Grade const& rhs)
{
   return lhs.id < rhs.id;   
}

其次我在UpdateSearchFields()执行之前在ViewModel构造函数中初始化我的属性:

private SearchField _dishField;
    public SearchField DishField {
        get
        {
            return _dishField;
        }
        set
        {
            _dishField = value;
            RaisePropertyChanged (() => DishField);
        }
    }