Android MvxBind CheckedChange SwitchCompat
我在将我的Android MvxBind CheckedChange SwitchCompat,android,xamarin,data-binding,bind,mvvmcross,Android,Xamarin,Data Binding,Bind,Mvvmcross,我在将我的Android.Support.V7.Widget.SwitchCompat绑定到我的viewmodel时遇到问题(我正在使用的框架是Mvvmcross) 我做的和另一个对象上的点击绑定完全一样,效果非常好 查看视图时出现的错误如下所示: 12-21 10:32:06.459 I/MvxBind (22969): 42,82 Failed to create target binding for binding CheckedChange for OnCheckedChanged [
Android.Support.V7.Widget.SwitchCompat
绑定到我的viewmodel时遇到问题(我正在使用的框架是Mvvmcross)
我做的和另一个对象上的点击绑定完全一样,效果非常好
查看视图时出现的错误如下所示:
12-21 10:32:06.459 I/MvxBind (22969): 42,82 Failed to create target binding for binding CheckedChange for OnCheckedChanged
[0:] MvxBind:Warning: 42,82 Failed to create target binding for binding CheckedChange for OnCheckedChanged
我拥有的开关数量增加了很多倍
他们说,这可能与链接器有关,但由于反射魔法的缘故,链接器不包括这些内容
这样,他们说您必须创建一个文件“LinkerPleaseInclude”,以保留对switchcompat的引用。我这样做如下,但错误仍然存在
LinkerPleaseInclude
class LinkerPleaseInclude
{
public void Include(TextView text)
{
text.AfterTextChanged += (sender, args) => text.Text = "" + text.Text;
text.Hint = "" + text.Hint;
}
public void Include(CompoundButton cb)
{
cb.CheckedChange += (sender, args) => cb.Checked = !cb.Checked;
cb.Hint = "" + cb.Hint;
}
public void Include(SwitchCompat cb)
{
cb.CheckedChange += (sender, args) => cb.Checked = !cb.Checked;
cb.Hint = "" + cb.Hint;
}
public void Include(ICommand command)
{
command.CanExecuteChanged += (s, e) => { if (command.CanExecute(null)) command.Execute(null); };
}
public void Include(CheckBox checkBox)
{
checkBox.CheckedChange += (sender, args) => checkBox.Checked = !checkBox.Checked;
}
}
我的视图布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/md_list_single_line_item_height"
android:gravity="center_vertical"
android:paddingLeft="@dimen/md_list_item_horizontal_edges_padding"
android:paddingRight="@dimen/md_list_item_horizontal_edges_padding">
<android.support.v7.widget.SwitchCompat
android:id="@+id/mySwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
local:MvxBind="Checked IsActive; Click OnSwitchClick; CheckedChange OnCheckedChanged" />
<TextView
android:id="@+id/Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textColor="@color/md_text_dark_primary_87"
android:textSize="@dimen/md_list_item_primary_text"
local:MvxBind="Text Name"/>
<TextView
android:id="@+id/Kind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:textColor="@color/md_text_dark_secondary_54"
android:textSize="@dimen/md_list_item_secondary_text"
android:layout_below="@+id/Name"
local:MvxBind="Text Kind"/>
</RelativeLayout>
此布局是另一布局的子布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/md_list_two_line_item_height"
android:paddingTop="?android:attr/actionBarSize"
android:fitsSystemWindows="true">
<MvxClickableLinearLayout
android:id="@+id/animalSelectionsList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:divider="@drawable/divider_horizontal"
android:showDividers="middle"
local:MvxBind="ItemsSource SelectionsList"
local:MvxItemTemplate="@layout/listitem_animal_selections" />
</LinearLayout>
CheckedChange
是一个事件,因此它不是公共属性。不能直接绑定MvvmCross中的事件,除非创建自己的目标绑定来处理此事件并公开命令
这可能看起来像:
public class MvxCompoundButtonCheckedChangeBinding : MvxAndroidTargetBinding
{
private ICommand _command;
private IDisposable _checkedChangeSubscription;
private IDisposable _canExecuteSubscription;
private readonly EventHandler<EventArgs> _canExecuteEventHandler;
protected CompoundButton View => (CompoundButton)Target;
public MvxCompoundButtonCheckedChangeBinding(CompoundButton view)
: base(view)
{
_canExecuteEventHandler = OnCanExecuteChanged;
_checkedChangeSubscription = view.WeakSubscribe<CompoundButton, CompoundButton.CheckedChangeEventArgs>(nameof(view.CheckedChange), ViewOnCheckedChangeClick);
}
private void ViewOnCheckedChangeClick(object sender, CompoundButton.CheckedChangeEventArgs args)
{
if (_command == null)
return;
if (!_command.CanExecute(null))
return;
_command.Execute(view.Checked);
}
protected override void SetValueImpl(object target, object value)
{
_canExecuteSubscription?.Dispose();
_canExecuteSubscription = null;
_command = value as ICommand;
if (_command != null)
{
_canExecuteSubscription = _command.WeakSubscribe(_canExecuteEventHandler);
}
RefreshEnabledState();
}
private void RefreshEnabledState()
{
var view = View;
if (view == null)
return;
var shouldBeEnabled = false;
if (_command != null)
{
shouldBeEnabled = _command.CanExecute(null);
}
view.Enabled = shouldBeEnabled;
}
private void OnCanExecuteChanged(object sender, EventArgs e)
{
RefreshEnabledState();
}
public override MvxBindingMode DefaultMode => MvxBindingMode.OneWay;
public override Type TargetType => typeof(ICommand);
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_checkedChangeSubscription?.Dispose();
_checkedChangeSubscription = null;
_canExecuteSubscription?.Dispose();
_canExecuteSubscription = null;
}
base.Dispose(isDisposing);
}
}
然后您可以将MyCheckedChange绑定到您的命令。我已将CompoundButton仅替换为SwitchCompat,因此它现在可以工作(并重命名为类):
公共类MvxButtonCheckedChangeBinding:MvxAndroidTargetBinding
{
专用ICommand_命令;
私有IDisposable _checkedChangeSubscription;
私人IDisposable(可执行认购);;
私有只读事件处理程序_canExecuteEventHandler;
公共静态字符串Name=“MyCheckedChange”;
受保护的CompoundButton视图=>(SwitchCompat)目标;
公共MvxButtonCheckedChangeBinding(SwitchCompat视图)
:底座(视图)
{
_canExecuteEventHandler=一旦CanExecuteChanged;
_checkedChangeSubscription=view.WeakSubscripte(名称为(view.CheckedChange),ViewOnCheckedChangeClick);
}
private void ViewOnCheckedChangeClick(对象发送者,SwitchCompat.CheckedChangeEventArgs args args)
{
变量视图=(SwitchCompat)发送方;
如果(视图==null | | | u命令==null)
返回;
如果(!\u命令.CanExecute(null))
返回;
_command.Execute(view.Checked);
}
受保护的覆盖无效SetValueImpl(对象目标,对象值)
{
_canExecuteSubscription?.Dispose();
_canExecuteSubscription=null;
_command=作为ICommand的值;
如果(_命令!=null)
{
_canExecuteSubscription=_command.WeakSubscribe(_CanExecuteSeventhandler);
}
RefreshEnabledState();
}
私有void RefreshEnabledState()
{
var视图=视图;
如果(视图==null)
返回;
var shouldBeEnabled=false;
如果(_命令!=null)
{
shouldBeEnabled=\u command.CanExecute(null);
}
view.Enabled=shouldBeEnabled;
}
私有void OnCanExecuteChanged(对象发送方,事件参数e)
{
RefreshEnabledState();
}
公共覆盖MvxBindingMode DefaultMode=>MvxBindingMode.OneWay;
公共覆盖类型TargetType=>typeof(ICommand);
受保护的覆盖无效处置(bool isDisposing)
{
if(isDisposing)
{
_checkedChangeSubscription?.Dispose();
_checkedChangeSubscription=null;
_canExecuteSubscription?.Dispose();
_canExecuteSubscription=null;
}
基础处理(isDisposing);
}
}
当然,别忘了像Cheesebaron在上面写的那样在安装类中注册它我不确定,但可能是因为android.support.v7.widget.SwitchCompat与复选框无关?它不支持CheckedChange?SwitchCompat是从CompoundButton派生的类型。就像复选框一样。CompoundButton有一个事件
CheckedChange
只能要求查看您的模型。对于链接器,请尝试在项目设置中以不同的方式设置android选项,以便链接器对sdk和用户程序集进行链接,或者不进行链接(不确定默认设置是什么)。只是为了测试是否是链接器的错误。@Cyriac我已将我的viewmodel上载到pastebin,因为它是一个相当大的模型,否则我会得到“您的问题包含的代码多于详细信息”错误说明这是内部viewmodel(在列表中),如果需要,我还可以上载父viewmodel。该设置设置为“非”,我在项目中重新创建了它,但它对我也不起作用。所以你要么等到我明天再看一遍,要么你在他们的github上问,你很可能会在哪里得到更快的答案。那么这门课是什么?这是可疑的!但正如@Cyriac提到的另一个类是什么?那个类是用于“已检查”源的,您已经在使用它了。对不起,不是源,而是目标。
registry.RegisterCustomBindingFactory<View>("MyCheckedChange",
view => new MvxCompoundButtonCheckedChangeBinding(view));
public class MvxButtonCheckedChangeBinding : MvxAndroidTargetBinding
{
private ICommand _command;
private IDisposable _checkedChangeSubscription;
private IDisposable _canExecuteSubscription;
private readonly EventHandler<EventArgs> _canExecuteEventHandler;
public static string Name = "MyCheckedChange";
protected CompoundButton View => (SwitchCompat)Target;
public MvxButtonCheckedChangeBinding(SwitchCompat view)
: base(view)
{
_canExecuteEventHandler = OnCanExecuteChanged;
_checkedChangeSubscription = view.WeakSubscribe<SwitchCompat, SwitchCompat.CheckedChangeEventArgs>(nameof(view.CheckedChange), ViewOnCheckedChangeClick);
}
private void ViewOnCheckedChangeClick(object sender, SwitchCompat.CheckedChangeEventArgs args)
{
var view = (SwitchCompat)sender;
if (view == null || _command == null)
return;
if (!_command.CanExecute(null))
return;
_command.Execute(view.Checked);
}
protected override void SetValueImpl(object target, object value)
{
_canExecuteSubscription?.Dispose();
_canExecuteSubscription = null;
_command = value as ICommand;
if (_command != null)
{
_canExecuteSubscription = _command.WeakSubscribe(_canExecuteEventHandler);
}
RefreshEnabledState();
}
private void RefreshEnabledState()
{
var view = View;
if (view == null)
return;
var shouldBeEnabled = false;
if (_command != null)
{
shouldBeEnabled = _command.CanExecute(null);
}
view.Enabled = shouldBeEnabled;
}
private void OnCanExecuteChanged(object sender, EventArgs e)
{
RefreshEnabledState();
}
public override MvxBindingMode DefaultMode => MvxBindingMode.OneWay;
public override Type TargetType => typeof(ICommand);
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_checkedChangeSubscription?.Dispose();
_checkedChangeSubscription = null;
_canExecuteSubscription?.Dispose();
_canExecuteSubscription = null;
}
base.Dispose(isDisposing);
}
}