问题与不使用MVVMCross编程相同,但我想知道是否存在“跨平台”解决方案:
在MvxBindableListView(或ListView)上使用ImageButton时,我们必须放置一些选项才能对此按钮使用操作:
<ImageButton
...
android:focusable="false"
android:clickable="true"
...
local:MvxBind="'Click':{'Path':'Command1'}}"
/>
使用这些参数,按钮会对“Command1”作出反应。 但问题是ListView的“视觉选择器”没有改变。
我们举个例子:
如果ListView中有5行,则选择第一行。我触摸第3行的ImageButton,“Command1”将作出反应(与ListView的第3项),但选择器将保持在第一行。
所以,在Android中,我们必须放置这样的代码:
_imagebutton.Click += (object sender, EventArgs eventsArgs) =>
{
View v = ...
MvxBindableListView l = ...
int p = l.GetPositionForView(...);
l.PerformItemClick(..., p, p);
};
使用这段代码选择正确的项目并且行为正确(只要我不想使用ItemClick触发真实事件)。但是这个解决方案是“Android方式”而不是真正的跨平台(我让你想象可怕的代码来初始化所有这些东西)
有人有更好的解决方案吗?
雨果
答案 0 :(得分:1)
部分地说,感觉这只是'UI eye candy' - 因此属于'View Concer'的范畴 - 因此mvvmcross通常不会尝试跨平台。
然而......我认为有办法。
如果ViewModel中的命令处理程序也在ViewModel上设置了一个CurrentSelectedPosition整数,那么每个UI都可以将SelectedItemPosition从ViewModel绑定到每个ui中的每个列表 - 这应该会导致UI本机更新选择。
我认为这样可行......但在Android上它需要一些绑定:
public class MvxAdapterViewSelectedItemPositionTargetB-inging : MvxBaseAndroidTargetBinding
{
private readonly AdapterView _adapterView;
public MvxAdapterViewSelectedItemPositionTargetBinging(AdapterView adapterView)
{
_adapterView = adapterView;
_adapterView.ItemSelected += AdapterViewOnItemSelected;
}
public override void SetValue(object value)
{
_adapterView.SetSelection((int)value);
}
private void AdapterViewOnItemSelected(object sender, AdapterView.ItemSelectedEventArgs itemSelectedEventArgs)
{
FireValueChanged(itemSelectedEventArgs.Position);
}
public override MvxBindingMode DefaultMode
{
get
{
return MvxBindingMode.TwoWay;
}
}
public override Type TargetType
{
get
{
return typeof(Int32);
}
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
if (_adapterView != null)
{
_adapterView.ItemSelected -= AdapterViewOnItemSelected;
}
}
base.Dispose(isDisposing);
}
}
使用注册:
registry.RegisterFactory(new MvxCustomBindingFactory<AdapterView>("SelectedItemPosition", adapterView => new MvxAdapterViewSelectedItemPositionTargetBinging(adapterView)));
并绑定到axml中的UI,例如为:
<Mvx.MvxBindableListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="{'ItemsSource':{'Path':'Emails'},'SelectedItemPosition':{'Path':'CurrentSelectedPosition'}}"
local:MvxItemTemplate="@layout/listitem_email"
/>
我使用一个电子邮件列表测试了这个想法,其中ViewModel列表项是:
public class SimpleEmail
{
public EmailViewModel Parent { get; set; }
public string From { get; set; }
public string Header { get; set; }
public string Message { get; set; }
public ICommand Command1
{
get
{
return new MvxRelayCommand(() => Parent.CurrentSelectedPosition = Parent.Emails.IndexOf(this));
}
}
}
注意:我在上面的代码中使用选定的位置而不是选定的对象 - 因为我知道你使用的列表很长!
如果你想考虑一种不同于android的代码的方法,那么我认为你可以通过继承Mvx.MvxBindableListView(也可能是列表项)并使用这些类来更新选择不太痛苦的方式。