Xamarin latest update findviewbyid returns null - visual-studio

I just installed the latest update of Xamarin for Visual Studio.
Ever since, android can't find the views in my activity layouts.
Apparently the auto-generated IDs aren't updated correctly when i just save my resources.
If I clean the project and rebuild, my app runs fine. But after like 20 minutes of coding the problem will occur again.
Simple code: Resources/Layout/Main.axml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="9dp"
android:paddingBottom="9dp">
<Button
android:text="#string/action_stockcount"
android:layout_width="match_parent"
android:layout_height="90dp"
android:id="#+id/btnStockCount"
android:layout_marginLeft="18dp"
android:layout_marginRight="18dp"
android:layout_marginStart="9dp"
android:layout_marginTop="9dp"
android:textColor="#color/menu_button_text"
android:textSize="30dp"
android:drawableLeft="#drawable/menu_stockcount_big"
android:paddingLeft="18dp"
android:paddingRight="18dp"
android:paddingBottom="9dp"
android:paddingTop="9dp" />
</LinearLayout>
</ScrollView>
MainActivity.designer.cs:
using ...
namespace MyApp.Droid.Activities
{
public partial class MainActivity
{
private Button btnStockCount;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
SetTitle(Resource.String.ApplicationName);
btnStockCount = FindViewById<Button>(Resource.Id.btnStockCount);
// From time to time, this gives a NullReferenceException
btnStockCount.Click += BtnStockCount_Click;
InitComplete(savedInstanceState);
}
}
}
MainActivity.cs (Not quite important):
using ...
namespace MyApp.Droid.Activities
{
public partial class MainActivity : Activity
{
private void BtnStockCount_Click(object sender, EventArgs e)
{
StartActivity(typeof(IndexStockCountActivity));
}
}
}
I know how android works, I know how Xamarin works. Why would the latest update of Xamarin cause this issue (the IDs that aren't updated correctly when saving a resource)? What can I do to solve this issue?
It's really annoying to have to debug my project, notice that again it's not working well, and having to clean and rebuild, and notice that after that it IS working.
I also already noticed that when it's not working, after I cleaned and rebuilded the Resource Ids are in fact changed.
Cheers

Related

Open another content page in Xamarin Form

I am trying to Navigate from MainPage to another ContentPage in Xamarin Forms, but it throws some un-descriptive error message. I am following Hierarchical Navigation, but it doesn't help. The error appears in Android and IOS, but I didn't check with UWP as it is not required.
My App.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
and in MainPage, I have button click event
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new Page1());
}
and Page1.cs and Page1.XAML
[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class Page1 : ContentPage
{
public Page1 ()
{
InitializeComponent();
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LocalDatabaseTutorial.Page1">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
and Also error message
At first, what is the error message? and How do I navigate from one page to another page in Xamarin forms?
Ensure that all your Xamarin.Forms have matching versions between your projects (.NetStd libraries containing the Xamarin.Forms package, Xamarin.Android|iOS application projects, etc...).
Typically (always?) a ...resolve type with token XXX from typeref... exception comes from a mismatch of a compiled/IL type from a runtime type (i.e. same assembly name but different version at runtime).

Xamarin MvvmCross MvxAppCompatDialogFragment looses BindingContext

I've been using MvxAppCompatActivity throughout my project, but in this specific case I have to make use of a MvxAppCompatDialogFragment.
Unfortunately, in this case I lose the binding context of the ViewModel somehow.
MobileTestView
[MvxDialogFragmentPresentation]
[Register(nameof(MobileScreenTestView))]
public class MobileTestView : MvxAppCompatDialogFragment<MobileTestViewModel>
...
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.Inflate(Resource.Layout.mobile_screen, container, false);
}
...
MobileTestViewModel
public class MobileTestViewModel : MvxViewModel<MInput, MResult>
...
public string Instructions { get; set; } = "Instructions";
...
mobile_screen.axml
...
<TextView
android:id="#+id/text_mobile"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center_vertical|center_horizontal"
tools:text="Scan"
local:MvxBind="Text Instructions" />
...
local:MvxBind="Text Instructions" does not work anymore, but I've checked and it is set in the view model before it gets to OnCreateView().
The above code would work fine for a MvxAppCompatActivity.
If what I'm trying to do is not possible, I can always do it like
view.FindViewById<TextView>(Resource.Id.text_mobile).Text = ViewModel.Instructions;
It's not that I really need to use local:MvxBind, but I would like to know what I'm doing wrong.
Update - For anyone having the same problem:
Change the OnCreateView method to:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.mobile_screen, container, false);
}
and your BindingContext will work fine.
As you noticed yourself, you had to use this.BindingInflate instead of the LayoutInflater argument in OnCreateView. This is because we have no way to intercept the Fragment lifecycle in MvvmCross to provide our own Layout Inflater.
What BindingInflate does, is to run through the view hierarchy and look for all the custom attributes applied on views, in your case Text Instructions and apply these bindings between the View and the ViewModel.
So whenever working with Fragments, you should use BindingInflate.

MvvmCross creating custom binding to LinearLayout

I am trying to create a custom binding to LinearLayout to allow me create a view dynamically and bind this as a child to LinearLayout. For anyone familiar with WPF, this is similar to the functionality provided by the ContentControl or any WPF control deriving from ContentControl. Basically you can create your dynamic content and bind to the Content property of a ContentControl.
Here's what I have for the custom binding:
public class MvxLinearLayoutContentTargetBinding : MvxPropertyInfoTargetBinding<LinearLayout>
{
public MvxLinearLayoutContentTargetBinding(object target, PropertyInfo targetPropertyInfo) : base(target, targetPropertyInfo)
{
}
protected override void SetValueImpl(object target, object value)
{
base.SetValueImpl(target, value);
var view = target as LinearLayout;
if (view == null) return;
view.AddView((View)value);
}
public override Type TargetType
{
get { return typeof(LinearLayout); }
}
}
Here's how I am attempting to use this new binding in my layout:
<?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="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingTop="3dp"
android:paddingLeft="5dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingTop="3dp"
android:paddingLeft="0dp"
local:MvxBind="Content CustomView">
</LinearLayout>
</LinearLayout>
Any my ViewModel looks like this:
public class CustomViewModel : MvxViewModel
{
public object CustomView { get; set; }
}
The custom binding has also been registered in Setup.cs as follows:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(
typeof(MvxLinearLayoutContentTargetBinding),
typeof(LinearLayout), "Content");
base.FillTargetFactories(registry);
}
Yet with all this in place, I do not see my view.
MvvmCross already supports a primitive version of this. Although without DataTemplateSelector.
You can bind a collection of ViewModels to MvxLinearLayout.ItemsSource. You also need to remember to set a ItemTemplateId:
<MvxLinearLayout
...
local:MvxItemTemplateId="#layout/layout_to_repeat"
local:MvxBind="ItemsSource ViewModelCollection"
/>
This is however super inefficient as it does not recycle views etc. So if you need a variant that supports DataTemplateSelector, then use MvxRecyclerView instead.

xamarin mvvmcross binding relative layout

I am new to mvvmcross. I do not know how to bind touch event of a relative layout to a view model. Can someone help me on this. Thanks in advance.
This is possible using standard MvvmCross code. For the viewmodel you can use something like:
public class SomeViewModel : MvxViewModel
{
public IMvxCommand OpenSomethingCommand { get; private set; }
public SomeViewModel ()
{
OpenSomethingCommand = new MvxCommand(() => ShowViewModel<SomeOtherNewViewModel>());
}
}
Then for the layout in your android project, you can use:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
local:MvxBind="Click OpenSomethingCommand"
android:id="#+id/someLayout">
//Wrap any other layouts in here
</RelativeLayout>

Custom ToggleButton findViewById Null Pointer

I have been trying to solve this problem for hours now and have exhausted all the obvious solutions. I have a custom toggle button that works fine as long as I don't try to get it using findViewById
Here is the relevant code:
public class WeekButton extends ToggleButton {
private static int mWidth;
public WeekButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WeekButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
...
}
Here is the layout..
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<org.myname.projetname.reminders.WeekButton.WeekButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mondayToggleButton"
style="#style/RecurrenceDayOfWeekStyle"
android:textOff=" Mon"
android:textOn=" Mon" />
</LinearLayout>
Exception occurs here..
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_reminder_activity);
//This causes null pointer
WeekButton weekButton = (WeekButton)findViewById(R.id.mondayToggleButton));
}
Thanks for any help you can provide!
SOLUTION: Turns out I forgot to instantiate the list I was adding the WeekButtons which made it look like the call to find id was working but it was. Thank you everyone you tried to help.
Didn't it show any error before run? xml name space attribute is given for the parent tag.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<org.myname.projetname.reminders.WeekButton.WeekButton
android:id="#+id/mondayToggleButton"
style="#style/RecurrenceDayOfWeekStyle"
android:textOff=" Mon"
android:textOn=" Mon" />
</LinearLayout>
Also, Cast to your class on findViewById().
Forgot to instantiate a list I was adding the weekbuttons to.

Resources