我正在使用MvxFrameControl在MyAccountView中重用AddressView。
<!-- MyAccountView.axml -->
<MvxFrameControl
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="DataContext EditAddressViewModel"
local:MvxTemplate="@layout/editaddressview"
android:id="@+id/EditAddressView" />
在MyAccountView,MyAccountFragment的android片段中,我想访问MvxFrameControl引用的布局中包含的EditText。
<!-- EditAddressView.axml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/SingleLineEditIconHeight"
local:MvxBind="Visibility Visibility(IsExpanded)">
<EditText
android:id="@+id/Address1"
style="@style/EditText"
android:layout_marginLeft="@dimen/MarginMedium"
android:layout_marginTop="@dimen/MarginSmall"
android:hint="@string/MyAccount_Address"
android:imeOptions="actionNext"
android:inputType="text"
local:MvxBind="Text Address1" />
</LinearLayout>
不幸的是,textViewAddress1返回null ...
// MyAccountFragment
View view = this.BindingInflate(this.layoutId, container, false);
var frameControl = view.FindViewById<MvxFrameControl>(Resource.Id.EditAddressView);
var textViewAddress1 = frameControl.FindViewById<EditText>(Resource.Id.Address1);
// textViewAddress1 == null
如何从MyAccountFragment中检索此视图?
编辑1:
看到MvxControl的源代码,很明显MvxFrameControl在这个阶段没有膨胀:
public MvxFrameControl(int templateId, Context context, IAttributeSet attrs)
: base(context, attrs)
{
_templateId = templateId;
if (!(context is IMvxLayoutInflater))
{
throw Mvx.Exception("The owning Context for a MvxFrameControl must implement LayoutInflater");
}
_bindingContext = new MvxAndroidBindingContext(context, (IMvxLayoutInflater)context);
this.DelayBind(() =>
{
if (Content == null && _templateId != 0)
{
Mvx.Trace("DataContext is {0}", DataContext == null ? "Null" : DataContext.ToString());
Content = _bindingContext.BindingInflate(_templateId, this);
}
});
}
通货膨胀被置于仅在设置了DataContext时执行的操作(如果我理解正确的话)。 所以我的问题很简单,在MvxFragment的哪一步,MvxFrameControl上设置了数据上下文?
答案 0 :(得分:1)
我找到了另一个解决方案。 在给视图充气后,添加此代码以强制延迟绑定发生:
BindingContext.DataContext = BindingContext.DataContext;
确保BindingContext.DataContext
不为空:)
答案 1 :(得分:0)
嗯,我不得不做一些非常丑陋的工作......
由于MvxFrameLayout只在DataContext发生变化时才会膨胀,这就是我现在在MvxFragment的OnCreateView中所拥有的内容:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
MvxTrace.Trace("MvxGenericFragment => OnCreateView");
View ignored = base.OnCreateView(inflater, container, savedInstanceState);
View view = this.BindingInflate(this.layoutId, container, false);
var frameControl = view.FindViewById<MvxFrameControl>(Resource.Id.EditAddressView);
frameControl.BindingContext.DataContextChanged += (sender, args) =>
{
var textViewAddress1 = this.View.FindViewById<EditText>(Resource.Id.Address1);
// textViewAddress1 is not null!
};
}
如果某人有更清洁的方法......
答案 2 :(得分:0)
几年后,MvxFrameControl 仍然不会膨胀子布局,直到设置了 DataContext。虽然 Roubachof 的解决方案有效,但我发现直接在 View 代码中而不是 AXML 文件中将 ViewModel 分配给 BindingContext.DataContext 更简单。
public class HomeView : MvxAppCompatActivity<HomeViewModel>
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.HomeView);
var frameControl = FindViewById<MvxFrameControl>(Resource.Id.frame_control);
// This will force the MvxFrameControl to inflate the child layout
frameControl.BindingContext.DataContext = ViewModel;
// Depending on your app design, you might use a child ViewModel
//frameControl.BindingContext.DataContext = ViewModel.ChildViewModel;
// Locate an EditText inside the MvxFrameControl
var editText = frameControl.FindViewById<EditText>(Resource.Id.edit_text);
注意:在大多数 UI 框架中,我会说父 UI 元素访问子元素内的 UI 元素是一种糟糕的设计,因为它破坏了封装。但是,由于 MvvmCross 不提供支持自定义视图的 C# 文件,这似乎是添加自定义功能的最佳选择。