我尝试使用自定义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 ();
}
答案 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);
}
}
然后它应该“工作”。用于灵感结帐的内容,例如MvxView或MvxTableViewCell。
或者你也可以通过实现类似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);
}
}