Android DataBinding - How to Bind A ViewGroup'

2019-09-19 08:57发布

问题:

I am developing an Android app in Xamarin.Android(C#). However, i do feel that this question can also be answered by any Java devs as well.

I am new in android development. Anyways, i created a fragment with just a LinearLayout and a TextView inside it. When i create the background class for it, i don't inherit(on in JAVA's word, extend) it from the Fragment class but rather from the LinearLayout class.

So, the MyFragment.cs file starts like this :

public class MyFragment : LinearLayout

The JAVA equivalent would be

public class MyFragment extends LinearLayout

(P.S. I have limited knowledge of JAVA and it's sytaxes).

Anyways, all works fine. I have an Initialize method(In JAVA, it should be the Init method) which inflates the view of the fragment. From the view, it tries to find the TextView with the given Id.

So, the codes looks like this :

public class MyFragment : LinearLayout
{
 Context mContext;
  private void Initialize(Context ctx)
  {
        //Inflating the layout
        mContext = ctx;
        var inflatorService = (LayoutInflater)ctx.GetSystemService(Context.LayoutInflaterService);
        View v = inflatorService.Inflate(Resource.Layout.MyFragmentView, this, false);
        this.AddView(v);
        GoalHeader = v.FindViewById<TextView>(Resource.Id.GoalHeader);
  }

All works pretty well this far. I then go on implementing the MVVM pattern, using MVVMLight library. I create a ViewModel as follows :

 public class Vm_MyFragment : ViewModelBase
{
    private string _goaltitle = "";
    public string GoalTitle
    {
        get { return _goaltitle; }
        set { Set(ref _goaltitle, value); }
    }
    public void SetTest()
    {
        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            GoalTitle = "Test";
        });
    }
}

Still, everything's good. The problem starts when i try to bind the TextView's text property to the ViewModel's GoalTitle property, as follows :

 private readonly List<Binding> _bindings = new List<Binding>();

 private void Initialize(Context ctx)
    {
        //Inflating the layout
        mContext = ctx;
        var inflatorService = (LayoutInflater)ctx.GetSystemService(Context.LayoutInflaterService);
        View v = inflatorService.Inflate(Resource.Layout.MyFragmentView, this, false);
        this.AddView(v);
        Vm_MyFragmentView viewmodel = new Vm_MyFragmentView();
        GoalHeader = v.FindViewById<TextView>(Resource.Id.GoalHeader);
        _bindings.Add(
            this.SetBinding(
                () => mainViewModel.GoalTitle,
                () => GoalHeader.Text));
    }

Note : Binding is from the GalaSoft.MvvmLight.Helpers namespace.

I add the fragment in my main view(I mean, MainActivity's view) and debug the app. Upon execution, i get the following error :

Could not activate JNI Handle 0xfff02a68 (key_handle 0x339790a) of Java type 'md55bfae9a06327fa0fdf207b4f768604b1/MyFragment' as managed type 'TestApp.MyFragment'.

Searching google, i realized that i am trying to bind the property before the view is even created(correct me if i'm wrong). The suggestions i found on other SO answers were either to put the code in the OnCreateView method or somehow delay the execution of the binding part's code.

The first solution didn't work for me as LinearLayout aka a View doesn't have such a method OnCreateView which i can override.

So, how am i supposed to bind the TextView to the ViewModel then? And also, am i on the right track on treating the fragment as a LinearLayout as i am inheriting from it?

回答1:

Im not familiar with MVVMLIght extension but if you are using a fragment as it is supposed to (ie. in a tablayout) you should inherit from a fragment like this (This is a v4 support fragment):

public class CategoryFragment : SupportFragment {
RecyclerView _recyclerView;
private View _view;

public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    _view = inflater.Inflate (Resource.Layout._CategoryLayout, container, false);

    // Get our RecyclerView layout:
    _recyclerView = _view.FindViewById<RecyclerView> (Resource.Id.categoryRecyclerView);

    // Instantiate the layout manager
    var linearLayoutManager = new LinearLayoutManager (Context, LinearLayoutManager.Vertical, false);
    _recyclerView.SetLayoutManager (linearLayoutManager);

    // Instantiate the adapter and pass in its data source:
    _adapter = new CategoryAdapter (_categories);
    //Register the item click handler with the adapter:
    _adapter.ItemClick += OnItemClick;
    // Plug the adapter into the RecyclerView:
    _recyclerView.SetAdapter (_adapter);
    return _view;
}

}