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

自定义类型的MvvmCross绑定属性到自定义视图,mvvm,binding,viewmodel,mvvmcross,custom-view,Mvvm,Binding,Viewmodel,Mvvmcross,Custom View,我尝试在视图模型中用自定义视图绑定自定义类型的属性,但在绑定器方法中“SetValue(object value)”的值始终为null。为什么会这样?是否无法在MvvmCross中将自定义类型的属性与自定义视图绑定 我的ViewModel: public class RecipesFiltersVM : MvxViewModel { public SearchField DishField { get; private set; } public SearchField Cuis

我尝试在视图模型中用自定义视图绑定自定义类型的属性,但在绑定器方法中“SetValue(object 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);
        }
    }
}
在活页夹中:

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);
    }
第二,在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 ();
    }
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 ();
    }
公共配方过滤器VM(IFiltersService过滤器服务)
{
_filtersService=filtersService;
DishField=newsearchfield(新列表());
CuisineField=新搜索字段(新列表());
IngreditField=新搜索字段(新列表());
UpdateSearchFields();
}

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

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);
    }
}
然后它就应该“起作用”了。为了获得灵感,可以检查一下诸如或之类的东西



或者,您也可以实现自己的MvxPropertyInfoTargetBinding,就像MvvmCross是如何处理UISegmentedControlBinding的一样。您需要为自定义视图创建自己的自定义绑定。例如,如果您遵循了使用公共C#属性和C#事件在自定义视图中定义项的常规MvvmCross实践,那么您应该能够执行以下操作:

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);
    }
}
然后它就应该“起作用”了。为了获得灵感,可以检查一下诸如或之类的东西


或者,您也可以实现自己的MvxPropertyInfoTargetBinding,就像MvvmCross是如何处理UISegmentedControlBinding的一样,通过实现以下内容。

用注释以两种方式解决更新ViewModel代码。首先,我更改了自定义属性声明,如:

private SearchField _dishField;
    public SearchField DishField {
        get
        {
            return _dishField;
        }
        set
        {
            _dishField = value;
            RaisePropertyChanged (() => DishField);
        }
    }
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 ();
    }
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 ();
    }
公共配方过滤器VM(IFiltersService过滤器服务)
{
_filtersService=filtersService;
DishField=newsearchfield(新列表());
CuisineField=新搜索字段(新列表());
IngreditField=新搜索字段(新列表());
UpdateSearchFields();
}
以两种方式用注释解决更新ViewModel代码。首先,我更改了自定义属性声明,如:

private SearchField _dishField;
    public SearchField DishField {
        get
        {
            return _dishField;
        }
        set
        {
            _dishField = value;
            RaisePropertyChanged (() => DishField);
        }
    }
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 ();
    }
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 ();
    }
公共配方过滤器VM(IFiltersService过滤器服务)
{
_filtersService=filtersService;
DishField=newsearchfield(新列表());
CuisineField=新搜索字段(新列表());
IngreditField=新搜索字段(新列表());
UpdateSearchFields();
}

你能发布更多的代码吗?e、 g.显示DishField设置为非空值的位置的完整视图模型?类似于N+1 MvxView视频的东西也可能有助于另一种方法-@Stuart我在ViewModel中添加了更多代码,我发现了我的问题。谢谢你的回答,这很有用。你能发布更多的代码吗?e、 g.显示DishField设置为非空值的位置的完整视图模型?类似于N+1 MvxView视频的东西也可能有助于另一种方法-@Stuart我在ViewModel中添加了更多代码,我发现了我的问题。谢谢你的回答,这很有用谢谢你的回答但解决方案更简单谢谢你的回答但解决方案更简单