Xamarin: Method does not have correct signature - c#

I am trying to create simple multi-screen App.
I added Content Page and button to it.
MapPage.xaml.cs:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MapPage : ContentPage
{
public MapPage ()
{
InitializeComponent ();
}
void ShowMap(object s, EventArgs e)
{
}
}
MapPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App14"
x:Class="App14.MapPage">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin Forms!" />
<Button Text="show map"
Clicked="ShowMap"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I am getting error: ShowMap Method does not have correct signature
What I am doing wrong?

change the event handler from private (the default if not specified) to protected
protected void ShowMap(object s, EventArgs e)
{
}

Related

Xamarin forms : How to get a value of Entry Text from another content page

I am learning xamaring forms,
I would like to get an Entry text from another xaml.cs file
Here my Entry in my first xaml file (content page) :
<Entry x:Name="UserName" Text="" Placeholder="enter your name" />
And in my second content page I would like to get the value : UserName.Text
I would like to use BindableProprety because I am using this Popup plugin, if there is another solution I ll take
Thanks in advance
You can solve it creating a PopupPage because you're using Rg.Plugins.Popup, place an Entry and send an event when user press a button.
I have created an small demo.
1. The ask user name popup page.
XAML
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
x:Class="xamstack.AskUserPopupPage"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
mc:Ignorable="d">
<StackLayout BackgroundColor="White" Padding="20"
VerticalOptions="Center" HorizontalOptions="Fill">
<Entry x:Name="UserEntry"/>
<Button Text="Submit" Clicked="ButtonSubmitUser_OnClicked"/>
</StackLayout>
</pages:PopupPage>
Code behind
public partial class AskUserPopupPage : PopupPage
{
public AskUserPopupPage()
{
InitializeComponent();
}
private void ButtonSubmitUser_OnClicked(object sender, EventArgs e)
{
OnUserSubmitted(UserEntry.Text);
}
public event EventHandler<string> UserSubmitted;
protected virtual void OnUserSubmitted(string e)
{
UserSubmitted?.Invoke(this, e);
}
}
2. Finally the ViewModel and the Page to display/ask the user name.
ViewModel:
public class UserPageViewModel : INotifyPropertyChanged
{
private string _userName;
public string UserName
{
get => _userName;
set
{
if (_userName != value)
{
_userName = value;
OnPropertyChanged(nameof(UserName));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Page XAML:
...
<ContentPage.BindingContext>
<UserPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Label Text="{Binding UserName,Mode=OneWay}"/>
<Button Text="Ask user" Clicked="ButtonAskUser_OnClicked"/>
</StackLayout>
...
Page code behind:
public partial class UserPage : ContentPage
{
public UserPage()
{
InitializeComponent();
}
private async void ButtonAskUser_OnClicked(object sender, EventArgs e)
{
var page = new AskUserPopupPage();
page.UserSubmitted += async (_, userName) =>
{
var vm = (UserPageViewModel) BindingContext;
vm.UserName = userName;
await Navigation.PopPopupAsync();
};
await Navigation.PushPopupAsync(page);
}
}

How to improve loading performance in Tabbed Page xamarin forms

I am trying to create bottom tabbed page in Xamarin forms and i am doing this for Android.
here i am using latest version of Xamarin Forms.
My sample Bottom tabbed page like below.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:SampleTabbedPage.Views"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.BarItemColor="Gray"
android:TabbedPage.BarSelectedItemColor="Blue"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleTabbed">
<!--Pages can be added as references or inline-->
<NavigationPage
Title="Main"
NavigationPage.HasNavigationBar="False">
<x:Arguments>
<views:SampleDetailsPage/>
</x:Arguments>
</NavigationPage>
<ContentPage Title="Tab 1" />
<ContentPage Title="Tab 2" />
</TabbedPage>
My sample details page like
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleDetailsPage"
BackgroundColor="Gray">
<ContentPage.Content>
<StackLayout>
<ListView BackgroundColor="White" ItemTapped="ListView_ItemTapped">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Mango</x:String>
<x:String>Banana</x:String>
<x:String>Pinaple</x:String>
<x:String>Apple</x:String>
<x:String>Avacado</x:String>
<x:String>Coconut</x:String>
<x:String>Dragan Fruit</x:String>
<x:String>Pomaganate</x:String>
<x:String>Wood Apple</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the navigation i am doing as follows
in App.xamal.cs
MainPage = new NavigationPage(new FirstPage());
I have simple first page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.FirstPage">
<ContentPage.Content>
<StackLayout>
<Button Text="Click Me!" Clicked="Button_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
here in button click event i do the navigation to "Sample Tabbed Page"
await Navigation.PushAsync(new SampleTabbed());
This is working fine.
but there is a performance issue.
if i run this and click on button in First page it is taking 3 seconds to load tabbed page.
if i remove list view in sample detail page it take 2 seconds to load.
but if i add just a content page to click event it take only milliseconds to load.
Am i doing some thing wrong with implementing tabbed page?
or
is there any way to improve the loading performance with tabbed pages.
A solution is to make the heavy pages load their content in a lazy manner, only when their tab becomes selected. This way, since these pages are now empty when TabbedPage is created, navigating to the TabbedPage suddenly becomes very fast!
1.create a behavior for the TabbedPage page, called ActivePageTabbedPageBehavior.
class ActivePageTabbedPageBehavior : Behavior<TabbedPage>
{
protected override void OnAttachedTo(TabbedPage tabbedPage)
{
base.OnAttachedTo(tabbedPage);
tabbedPage.CurrentPageChanged += OnTabbedPageCurrentPageChanged;
}
protected override void OnDetachingFrom(TabbedPage tabbedPage)
{
base.OnDetachingFrom(tabbedPage);
tabbedPage.CurrentPageChanged -= OnTabbedPageCurrentPageChanged;
}
private void OnTabbedPageCurrentPageChanged(object sender, EventArgs e)
{
var tabbedPage = (TabbedPage)sender;
// Deactivate previously selected page
IActiveAware prevActiveAwarePage = tabbedPage.Children.OfType<IActiveAware>()
.FirstOrDefault(c => c.IsActive && tabbedPage.CurrentPage != c);
if (prevActiveAwarePage != null)
{
prevActiveAwarePage.IsActive = false;
}
// Activate selected page
if (tabbedPage.CurrentPage is IActiveAware activeAwarePage)
{
activeAwarePage.IsActive = true;
}
}
}
2.define IActiveAware interface
interface IActiveAware
{
bool IsActive { get; set; }
event EventHandler IsActiveChanged;
}
3.create a base generic abstract class called LoadContentOnActivateBehavior
abstract class LoadContentOnActivateBehavior<TActivateAwareElement> : Behavior<TActivateAwareElement>
where TActivateAwareElement : VisualElement
{
public DataTemplate ContentTemplate { get; set; }
protected override void OnAttachedTo(TActivateAwareElement element)
{
base.OnAttachedTo(element);
(element as IActiveAware).IsActiveChanged += OnIsActiveChanged;
}
protected override void OnDetachingFrom(TActivateAwareElement element)
{
(element as IActiveAware).IsActiveChanged -= OnIsActiveChanged;
base.OnDetachingFrom(element);
}
void OnIsActiveChanged(object sender, EventArgs e)
{
var element = (TActivateAwareElement)sender;
element.Behaviors.Remove(this);
SetContent(element, (View)ContentTemplate.CreateContent());
}
protected abstract void SetContent(TActivateAwareElement element, View contentView);
}
4.the specialized LazyContentPageBehavior
class LazyContentPageBehavior : LoadContentOnActivateBehavior<ContentView>
{
protected override void SetContent(ContentView element, View contentView)
{
element.Content = contentView;
}
}
then we can use in xaml like this:
<TabbedPage>
<TabbedPage.Behaviors>
<local:ActivePageTabbedPageBehavior />
</TabbedPage.Behaviors>
<ContentPage Title="First tab">
<Label Text="First tab layout" />
</ContentPage>
<local:LazyLoadedContentPage Title="Second tab">
<ContentPage.Behaviors>
<local:LazyContentPageBehavior ContentTemplate="{StaticResource ContentTemplate}" />
</ContentPage.Behaviors>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ContentTemplate">
<!-- Complex and slow to render layout -->
<local:SlowContentView />
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
</local:LazyLoadedContentPage>
</TabbedPage>
we moved the ContentPage complex layout to become a DataTemplate.
Here's the custom LazyLoadedContentPage page which is activation aware:
class LazyLoadedContentPage : ContentPage, IActiveAware
{
public event EventHandler IsActiveChanged;
bool _isActive;
public bool IsActive
{
get => _isActive;
set
{
if (_isActive != value)
{
_isActive = value;
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
SlowContentView do some complex things
public partial class SlowContentView : ContentView
{
public SlowContentView()
{
InitializeComponent();
// Simulating a complex view
...
}
}

Xamarin Effect affecting other controls

I am experiencing a weird bug where a Custom effect would affect other Controls as well while i am only targeting one specific control. I was able to reproduce the behavior in a small test project. What i am trying to achieve is to change the color of a specific entry control. It does work but when navigating back to the previous page the effect affects other controls as well while i only want the specific effect to affect a specific control. I also only add the effect to the specific Entry by using its Effects list from xaml.
(note i am using the standard forms navigation page for navigating defined in my app.xaml like this.
MainPage = new NavigationPage(new MainPage());
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Entry></Entry>
<Button Clicked="Button_Clicked" Text="navigate"></Button>
<Button Clicked="Button_Clicked2" Text="navigate to other"></Button>
</StackLayout>
</ContentPage>
CodeBehind of MainPage.xaml
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test());
}
private void Button_Clicked2(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test2());
}
}
Test.Xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.Test">
<ContentPage.Content>
<Entry>
<Entry.Effects>
<local:EntryLineColorEffect></local:EntryLineColorEffect>
</Entry.Effects>
</Entry>
</ContentPage.Content>
</ContentPage>
Test2.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Test2">
<ContentPage.Content>
<StackLayout>
<Label Text="test 2" />
<Entry>
</Entry>
</StackLayout>
</ContentPage.Content>
</ContentPage>
EntryLineColorEffect (forms project)
public class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("Prolang.EntryLineColorEffect")
{
}
}
EntryLineColorEffect (Android project)
[assembly: ResolutionGroupName("Prolang")]
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]
namespace App2.Droid.Effects
{
class EntryLineColorEffect : PlatformEffect
{
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
}
}
some screenshots that make it more clear
The entry does get the Magenta color which is good
But when navigating back and then navigating to the Test2 page that entry is also getting the Magenta color which for me is undesired behavior (and i do not know why it is hapenning). So what should i do to avoid this behavior?
In the end someone on the Xamarin comunity forum was able to answer my question.
=>
Effect won't affect other controls which haven't attached that effect. It seems Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); changes the global Entry's underline's color. The entry displayed later after this setting will apply this behavior. So your Test2's Entry still has an attacted style. Use Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); instead to correct that:
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}

Access Method from other Class in Xamarin

I'm stuck with a Xamarin problem. I have a XAML ContentPage file which consists of two ContentView (vm:) in a StackLayout:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Proj1"
xmlns:vm="clr-namespace:Proj1.ViewModels"
x:Class="Proj1.MyMain">
<StackLayout BackgroundColor="{StaticResource MainBG}" Spacing="1">
<vm:DisplayArea />
<vm:ButtonArea />
</StackLayout>
</ContentPage>
The two vm: presents two ContentView areas for labels and buttons. I separated these for simplicity and to keep the XAML files smaller.
So, the general, merged XAML structure looks like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Proj1"
xmlns:vm="clr-namespace:Proj1.ViewModels"
x:Class="Proj1.MyMain">
<StackLayout BackgroundColor="{StaticResource MainBG}" Spacing="1">
<ContentView>
...
<Label Grid.Row="0" Grid.Column="1" x:Name="InpRegX" />
...
</ContentView>
<ContentView>
...
<Button ... Clicked="BtnClicked" />
...
</ContentView>
</StackLayout>
</ContentPage>
But I want to have the two ContentView in separate files.
DisplayArea consists among others of a label RegX:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Proj1.ViewModels.DisplayArea">
...
<Label Grid.Row="0" Grid.Column="1" x:Name="InpRegX" />
...
</ContentView>
namespace Proj1.ViewModels
{
public partial class DisplayArea : ContentView
{
public readonly MyClass RegX; // made public for simplicity
public DisplayArea ()
{
InitializeComponent ();
RegX = new MyClass(InpRegX);
}
}
}
Now I want to execute a method .AddChar() of DisplayArea.RegX from a button clock.
namespace Proj1.ViewModels
{
public partial class ButtonArea : ContentView
{
public ButtonArea ()
{
InitializeComponent ();
}
private void BtnClicked(object sender, EventArgs e)
{
var btn = (Button)sender;
DisplayArea.RegX.AddChar(btn.Text); // ERROR!
}
}
}
This creates a compiler error:
An object reference is required for the non-static field, method, or property 'DisplayArea.RegX
This is because I reference RegX via its class, not the real object instance. But how can I find the name the compiler creates for the instance?
The standard in OOP is to create a static class for the utilities with static methods that are global and accessable as you did without creating an instance of the class every time you want to access a variable or a method.
Example:
public static class Util
{
public static string GlobalString = "Hello World";
public static string GetCurrentLanguage()
{
string SelectedLangProp;
if (Application.Current.Properties.ContainsKey("SelectedLangProp"))
{
SelectedLangProp = Application.Current.Properties["SelectedLangProp"] as string;
}
else
{
SelectedLangProp = "AR";//default language
}
return SelectedLangProp;
}
}
You can access static variables from anywhere using:
String TestGlobal = Util.GlobalString; //"Hello World"
Same goes for method calls:
String MethodResult = Util.GetCurrentLanguage();
There is an alternative way which is closer to what you asked which is:
DisplayArea display = new DisplayArea();
String Result = display.RegX.AddChar(btn.Text);
This will work but it will create a new instance of the class which is not recommended especially because you are using a contentview class and doing the logic in the code behind instead of using MVVM is the the recommended structure for building Xamarin apps.
in your XAML, assign a name
<vm:DisplayArea x:Name="MyDisplayArea />
then in your xaml.cs
private void BtnClicked(object sender, EventArgs e)
{
var btn = (Button)sender;
MyDisplayArea.RegX.AddChar(btn.Text); // ERROR!
}

How to get an image to pop up when a button is clicked in a xamarin forms app?

Hello I am working on a xamarin forms app the displays a map and when the user clicks a button the maps legend image pops up on top of the map. I am using this nuget package to get the popup effect: Rtorgames Popup package
the issue is that when I click the button the popup works but no legend image is showing up and the images are in the correct directories for both iOS and android.
heres my xaml code for the MapPage.xaml:
<?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="AppName.Forms.Pages.Map">
<ContentView x:Name="contentView" ControlTemplate="{StaticResource MapNavBar}">
<StackLayout>
<Button Text = "Legand" HorizontalOptions = "End" VerticalOptions="End" Clicked="legend_OnClicked"></Button>
<Grid HorizontalOptions="FillAndExpand" >
<Image Source="Map.png" Scale="1.0" Aspect="AspectFit" />
</Grid>
</StackLayout>
</ContentView>
</ContentPage>
here's the code behind for MapPage.xaml:
using System;
using Rg.Plugins.Popup.Extensions;
using Rg.Plugins.Popup.Services;
using Xamarin.Forms;
namespace AppName.Forms.Pages
{
public partial class Map : ContentPage
{
public Map()
{
InitializeComponent();
}
private async void legend_OnClicked(object sender, EventArgs e)
{
var page = new LegendPage();
await Navigation.PushPopupAsync(page);
}
}
}
here's the legendPage xaml code:
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
x:Class="AppName.Forms.Pages.LegendPage">
<StackLayout>
<Grid HorizontalOptions="FillAndExpand" >
<Image Source="legend.png" Scale="1.0" Aspect="AspectFit" />
</Grid>
</StackLayout>
</pages:PopupPage>
and finally here's the code behind to the legendPage.xaml:
using Xamarin.Forms;
using System;
using Rg.Plugins.Popup.Pages;
using System.Threading.Tasks;
namespace AppName.Forms.Pages
{
public partial class LegendPage : PopupPage
{
public LegendPage()
{
}
protected override void OnAppearing()
{
base.OnAppearing();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
}
// Method for animation child in PopupPage
// Invoced after custom animation end
protected override bool OnBackButtonPressed()
{
// Prevent hide popup
//return base.OnBackButtonPressed();
return true;
}
// Invoced when background is clicked
protected override bool OnBackgroundClicked()
{
// Return default value - CloseWhenBackgroundIsClicked
return base.OnBackgroundClicked();
}
}
}
any help would be amazing!
Thanks in advance! :)

Categories