私はかなりの数のフラグメントを持っていますが、それらはレイアウトで 90% 共通です。そして、私はコードからのレイアウトが本当に好きなので (もう iOS 用の XIB を作成したことはありません)、Android でも同じようにしようと思いました。それは思ったほど簡単ではありませんでした。問題は MvvmCross にあり、Web で解決策を探すと、解決策を示すヒントしか見つかりません。
問題: フラグメントが表示され、バインドを実行すると、null オブジェクトにバインドしようとするため、ソース プロパティが見つからないというすべてのメッセージが表示されます。
Unable to bind: source property source not found Cirrious.MvvmCross.Binding.Parse.PropertyPath.PropertyTokens.MvxPropertyNamePropertyToken on null-object
レイアウトが画面に表示され、ViewModel が設定され、bindingcontext が設定されます (自動的に行われなかったので、どちらも自分で作成しました)。
作成されたコントロールを「登録」するためにインフレで何かが行われていると思われます。インフレを使用していないため、登録されていません。MvxBindingContextStackRegistration に関する他の質問を読み、そのソースを見ました。2 番目の原因は bindingcontext 自体にある可能性があります。どういうわけか自動的に処理されず、以下のコードで必要な不足している beging が呼び出されていることを示しています。
これはそれを機能させるための最後の試みであるため、私は奇妙なことをしたかもしれません:
public class IndexTocFragment : MvxFragment
{
// two statics to save on typing
public static int WRAP = ViewGroup.LayoutParams.WrapContent;
public static int FILL = ViewGroup.LayoutParams.FillParent;
public LinearLayout NewVerticalLinearLayout(Orientation orientation, Boolean fillparent) {
var ll = new LinearLayout (Activity) { Orientation = orientation };
ll.LayoutParameters = new ViewGroup.LayoutParams (FILL, fillparent ? FILL : WRAP);
return ll;
}
public new IndexTocViewModel ViewModel { get { return base.ViewModel as IndexTocViewModel; } set { base.ViewModel = value; } }
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);
var layout = NewVerticalLinearLayout (Orientation.Vertical, true);
if (ViewModel == null)
ViewModel = Mvx.IocConstruct<IndexTocViewModel> ();
BindingContext = new MvxAndroidBindingContext (Activity, new MvxSimpleLayoutInflater(inflater));
using (new MvxBindingContextStackRegistration<IMvxAndroidBindingContext>(((IMvxAndroidBindingContext) this.BindingContext)))
{
//var layout = NewVerticalLinearLayout (Orientation.Vertical, true);
layout.SetBackgroundColor (Color.ParseColor("#FFFFFF"));
var titlelayer = NewVerticalLinearLayout (Orientation.Horizontal, false);
titlelayer.LayoutParameters.Height = 40;
var title = new TextView (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, FILL) };
title.SetTextColor (Color.ParseColor ("#212121"));
var titlebutton = new Button (Activity) { LayoutParameters = new ViewGroup.LayoutParams (WRAP, FILL) };
titlelayer.AddView (title);
titlelayer.AddView (titlebutton);
layout.AddView (titlelayer);
var twobuttonlayer = NewVerticalLinearLayout (Orientation.Horizontal, false);
twobuttonlayer.LayoutParameters.Height = 40;
var twobuttonklein = new Button (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
twobuttonklein.Text = "Klein";
twobuttonklein.SetBackgroundResource (Resource.Drawable.kleingrootbutton);
var twobuttongroot = new Button(Activity){ LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
twobuttongroot.Text = "Middel/groot";
twobuttongroot.SetBackgroundResource (Resource.Drawable.kleingrootbutton);
twobuttonlayer.AddView (twobuttonklein);
twobuttonlayer.AddView (twobuttongroot);
layout.AddView (twobuttonlayer);
var zoekvak = new EditText (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP) };
zoekvak.Hint = "Zoek in inhoudsopgave";
layout.AddView (zoekvak);
var emptytext = new TextView (Activity) { LayoutParameters = new ViewGroup.LayoutParams (FILL, WRAP),
Text = "Er zijn geen resultaten." };
emptytext.SetBackgroundColor (Color.ParseColor ("#BBAA00"));
layout.AddView (emptytext);
var listadapter = new BindableExpandableListAdapter(this.Activity, (IMvxBindingContext) BindingContext);
var list = new BindableExpandableListView (Activity, null, listadapter) { LayoutParameters = new ViewGroup.LayoutParams (FILL, FILL) };
list.SetMinimumHeight (50);
list.ItemTemplateId = Resource.Layout.indextocsectionlistitem;
list.GroupTemplateId = Resource.Layout.indextocitem;
list.SetGroupIndicator (null);
list.SetBackgroundColor (Color.ParseColor ("#AAAA00"));
layout.AddView (list);
this.DoBind += () => {
var bs = this.CreateBindingSet<IndexTocFragment, IndexTocViewModel> ();
if (ViewModel == null) {
Console.WriteLine ("ERROR ViewModel not set");
}
if (BindingContext == null) {
Console.WriteLine ("ERROR BindingContext not set");
}
bs.Bind (title).For (x => x.Text).To (vm => vm.IndexTitle);
// the following title displays some data from the ViewMode, and that works OK.
Console.WriteLine("Index title value: "+ViewModel.IndexTitle);
bs.Bind (twobuttongroot).For ("Click").To (vm => vm.SwitchKleinGrootCommand);
bs.Bind (twobuttonklein).For ("Click").To (vm => vm.SwitchKleinGrootCommand);
bs.Bind (zoekvak).For (x => x.Text).To (vm => vm.SearchText);
bs.Bind (emptytext).For (x => x.Text).To (vm => vm.TextForEmptyList);
bs.Bind (listadapter).For(x => x.ItemsSource).To(vm => vm.Chapters);
bs.Apply ();
};
// the next binding was never called
//this.DelayBind (() => {
//
//});
}
//var view = this.BindingInflate(Resource.Layout.IndexTocView, null);
Console.WriteLine ("LAYOUT RETURNED");
return layout;
}
private Action DoBind;
public override void OnResume()
{
// doing the binding here to make sure everything should have been set,
but it is of course not the logical location
base.OnResume();
Console.WriteLine ("RESUMING");
if (DoBind != null)
DoBind ();
}
}
今のところ、必要なすべての要素を含むフラグメント レイアウトを作成し、不要な要素を非表示にします。これでおそらくうまくいくでしょう。しかし、コードからのビューの作成を使用できることを願っています。
助けてくれてありがとう。
ところで: アクティビティとプレゼンターのコードは、MvvmCross のフラグメントの例から取られたカスタム プレゼンター コードです。Android のコードでのバインディング: Android 用MVVMCross - コードでバインディングを行う方法は? スタックにコンテキストをプッシュする: MvvmCross: カスタム アダプターを使用して MvxListView をプログラムで構築する方法は?