MvvmCross binding 属性 自定义类型到自定义视图
MvvmCross binding property of custom type to custom view
我尝试在 View Model 中使用自定义 View 绑定 属性 自定义类型,但在 Binder 方法中 "SetValue(object value)" 值始终为 null。为什么会这样?是否无法在 MvvmCross 中将自定义类型 属性 与自定义视图绑定?
我的视图模型:
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 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 ();
}
您需要为自定义视图创建自己的自定义绑定。例如,如果您遵循了使用 public 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);
}
}
然后它应该只是 "work." 为了获得灵感,检查诸如 MvxView or MvxTableViewCell.
之类的东西
或者,您可以像 MvvmCross 处理 UISegmentedControlBindings 的方式那样通过实现 MvxUISegmentedControlSelectedSegmentTargetBinding.
解决了 注释以两种方式更新 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 ();
}
我尝试在 View Model 中使用自定义 View 绑定 属性 自定义类型,但在 Binder 方法中 "SetValue(object value)" 值始终为 null。为什么会这样?是否无法在 MvvmCross 中将自定义类型 属性 与自定义视图绑定?
我的视图模型:
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 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 ();
}
您需要为自定义视图创建自己的自定义绑定。例如,如果您遵循了使用 public 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);
}
}
然后它应该只是 "work." 为了获得灵感,检查诸如 MvxView or MvxTableViewCell.
之类的东西或者,您可以像 MvvmCross 处理 UISegmentedControlBindings 的方式那样通过实现 MvxUISegmentedControlSelectedSegmentTargetBinding.
解决了
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 ();
}