How to configure Xamarin Webview to display an automatic height according to html content?
I am developing a news app in Xamarin and I have this problem, because the webview forces me to inform the height and the width to display the information and as my content is dynamic, (always changes) ends up being an empty space on screen!
Sorry for english, I used google translate!
Thanks!
Code: PostView.cs
namespace AppNewsPlay.Views
{
public partial class PostView : TabbedPage
{
private int object_id;
// Criando a Listagem de Ultimas Noticias Playstation
List<PostViewModels> UPost;
public TabbedPage Detail { get; private set; }
public PostView(int object_id)
{
this.object_id = object_id;
UPost = new List<PostViewModels>();
ObterPost();
InitializeComponent();
}
private async void ObterPost()
{
var resp = string.Empty;
try
{
var uri = new HttpClient()
{
BaseAddress = new Uri("http://api.newsplay.com.br")
};
var url = "/api/post/" + this.object_id;
var result = await uri.GetAsync(url);
if (!result.IsSuccessStatusCode)
{
await DisplayAlert("Erro de Conexão", "Não foi possível obter as notícias do servidor, Tente novamente mais tarde!", "OK");
return;
}
resp = await result.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
await DisplayAlert("Erro de Conexão com o Servidor", ex.Message, "OK");
return;
}
// transformando o retorno em objeto através do json e deserealize e retornando em lista
var UPost = JsonConvert.DeserializeObject<List<PostViewModels>>(resp);
var browser = new WebView();
// var htmlsource = new UrlWebViewSource();
foreach (var item in UPost)
{
var html = item.Guid;
browser.Source = html;
}
// Adicionando os itens ao ListView na Home.xaml - Aba Playstation*/
PostViewList.ItemsSource = UPost;
// ProgressLoader.IsRunning = false;
}
Code: PostView.xaml
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AppNewsPlay.Views.PostView"
Title="Voltar"
Icon=""
BarBackgroundColor="#1c9e33"
>
<TabbedPage.Children>
<ContentPage Title="Notícia" Icon="ic_filter_list_black_24dp.png">
<ContentPage.Content >
<StackLayout
Spacing="20">
<ListView x:Name="PostViewList"
HasUnevenRows="True"
SeparatorColor="White"
SeparatorVisibility="Default"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
Padding="20"
Orientation="Vertical"
>
<Label x:Name="Post_title" Text="{ Binding Post_title }"
FontSize="20"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
/>
<Label x:Name="Post_ad" Text="{Binding Post_ad}"
FontSize="12"
HorizontalTextAlignment="Center"
/>
<WebView HorizontalOptions= "FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="3500"
WidthRequest="650"
x:Name="browser"
Source="{Binding Guid}"
>
</WebView>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
</TabbedPage.Children>
</TabbedPage>
Related
I have a Xamarin Forms App with a Carousel View and my plan is to filter the result by the Priorities shown in a Bottom Tap Bar.
When the View is on the first card, everything works fine, but if you hit one of the filters from a different card, then the first one, a System.ArgumentOutOfRangeException exception got fired.
I tried already a lot of things to set the position of the Carousel View to 0, but in vain.
using the CarouselView_PositionChanged event => not working
using the TabHost_SelectedTabIndexChanged event => not working
setting the property of the CarouselView by the selectedIndex changed from the Tab View from the ViewModel => not working
turn it into a CollectionView and everything is working => just looks ugly 🤮
Here the page
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:viewModels="clr-namespace:AmsXamarin.ViewModels"
xmlns:fontAwesome="clr-namespace:FontAwesome"
xmlns:cells="clr-namespace:AmsXamarin.Cells"
xmlns:tabs="http://sharpnado.com"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:Class="AmsXamarin.Views.SnagListX.SnagListPage"
x:Name="mySnagListPage">
<ContentPage.BindingContext>
<viewModels:SnagListViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<xct:TabSelectionChangedEventArgs x:Key="TabSelectionChangedEventArgs" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Command="{Binding ShowMyJobsCommand}"
Order="Primary"
Priority="0"
Text="{Binding MyJobsTitle,Mode=TwoWay}">
</ToolbarItem>
<ToolbarItem Command="{Binding AddFaultCommand}"
Order="Primary"
Priority="0">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="FAS"
Glyph="{x:Static fontAwesome:FontAwesomeIcons.Plus}"
Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
Size="Large" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
<ToolbarItem Command="{Binding AcceptCommand}"
Order="Primary"
Priority="0">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="FAS"
Glyph="{x:Static fontAwesome:FontAwesomeIcons.UserCheck}"
Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
Size="Large" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<Label Style="{StaticResource LabelLarge}"
Text="Snag List"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<StackLayout>
<IndicatorView x:Name="snagListIndicator"
Margin="0,10,0,0"
IndicatorColor="LightGray"
SelectedIndicatorColor="LightGray"
IndicatorSize="6" />
<RefreshView Command="{Binding RefreshCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
Style="{StaticResource BaseRefreshView}">
<CarouselView x:Name="snagListCV"
Margin="10"
IndicatorView="snagListIndicator"
ItemsLayout="HorizontalList"
ItemsSource="{Binding SnagListPriorities.SnagListApps}"
CurrentItem="{Binding SnagListItem}"
Position="{Binding PositionIdx,Mode=OneWay}"
PositionChanged="CarouselView_PositionChanged"
Loop="False"
IsEnabled="{Binding IsNotBusy}">
<CarouselView.EmptyView>
<StackLayout Padding="12">
<Label Style="{StaticResource LabelMedium}"
HorizontalOptions="Center"
Text="{Binding EmptyMessage,Mode=TwoWay}" />
</StackLayout>
</CarouselView.EmptyView>
<CarouselView.ItemTemplate>
<DataTemplate>
<cells:SnagListCardX />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</RefreshView>
</StackLayout>
<tabs:TabHostView x:Name="TabHost"
Margin="13,0,13,10"
BackgroundColor="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Fourth}}"
CornerRadius="30"
IsSegmented="True"
Orientation="Horizontal"
TabType="Fixed"
SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}"
Shades="{StaticResource LightBottomShadow}">
<tabs:TabHostView.Behaviors>
<xct:EventToCommandBehavior EventName="SelectedTabIndexChanged"
Command="{Binding SelectedCommand}"
EventArgsConverter="{StaticResource TabSelectionChangedEventArgs}" />
</tabs:TabHostView.Behaviors>
<tabs:TabHostView.Tabs>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="All">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource All}"
TextColor="White"
Text="{Binding SnagListPriorities.All,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="High"
StyleClass="">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource High}"
TextColor="White"
Text="{Binding SnagListPriorities.High,Mode=OneWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="Medium">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource Medium}"
TextColor="Black"
Text="{Binding SnagListPriorities.Medium,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
<tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
Label="Low">
<tabs:BottomTabItem.Badge>
<tabs:BadgeView Style="{StaticResource BadgeViewBase}"
BackgroundColor="{StaticResource Low}"
TextColor="Black"
Text="{Binding SnagListPriorities.Low,Mode=TwoWay}" />
</tabs:BottomTabItem.Badge>
</tabs:BottomTabItem>
</tabs:TabHostView.Tabs>
</tabs:TabHostView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the view model
using AmsXamarin.Helpers;
using AmsXamarin.Models;
using AmsXamarin.Services;
using MvvmHelpers;
using MvvmHelpers.Commands;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Command = MvvmHelpers.Commands.Command;
namespace AmsXamarin.ViewModels
{
public class SnagListViewModel : BaseViewModel
{
readonly ISnagListService snagListService;
List<SnagListAppX> SnagListAppXs;
SnagListAppX snagListItem;
public SnagListAppX SnagListItem
{
get { return snagListItem; }
set
{
snagListItem = value;
OnPropertyChanged();
}
}
SnagListPriorities snagListPriorities;
public SnagListPriorities SnagListPriorities
{
get { return snagListPriorities; }
set
{
snagListPriorities = value;
OnPropertyChanged();
}
}
public AsyncCommand AddFaultCommand { get; }
public AsyncCommand AcceptCommand { get; }
public Command RefreshCommand { get; }
public Command SelectedCommand { get; }
public Command ShowMyJobsCommand { get; }
string emptyMessage;
public string EmptyMessage
{
get { return emptyMessage; }
set
{
emptyMessage = value;
OnPropertyChanged();
}
}
int positionIdx;
public int PositionIdx
{
get { return positionIdx; }
set
{
positionIdx = value;
OnPropertyChanged();
}
}
int selectedIndex;
public int SelectedIndex
{
get => selectedIndex;
set => SetProperty(ref selectedIndex, value);
}
string myJobsTitle = "My Jobs";
int staffId;
public string MyJobsTitle
{
get { return myJobsTitle; }
set
{
myJobsTitle = value;
OnPropertyChanged();
}
}
bool myJobsEnabled = true;
bool updateProperty = false;
public bool AcceptToolBar { get; set; }
public SnagListViewModel()
{
SnagListItem = new SnagListAppX();
SnagListPriorities = new SnagListPriorities()
{
SnagListApps = new ObservableRangeCollection<SnagListAppX>()
};
SnagListAppXs = new List<SnagListAppX>();
AddFaultCommand = new AsyncCommand(ShowAddSnagListItem);
AcceptCommand = new AsyncCommand(ShowModalAccept);
SelectedCommand = new Command(Selected);
RefreshCommand = new Command(Refresh);
staffId = 0;
ShowMyJobsCommand = new Command(ShowModalMyJobs);
snagListService = DependencyService.Get<ISnagListService>();
Device.BeginInvokeOnMainThread(async () =>
{
await GetSnagListItems();
});
}
async Task GetSnagListItems()
{
try
{
IsBusy = true;
EmptyMessage = "Loading...";
SnagListPriorities slp = await snagListService.GetSnagLists(false, true);
SnagListPriorities.SnagListApps.Clear();
SnagListPriorities = slp;
SnagListAppXs.Clear();
SnagListAppXs.AddRange(slp.SnagListApps);
EmptyMessage = SnagListAppXs.Count == 0 ? "Good Job! \r\n\r\nCurrently nothing to fix" : "";
IsBusy = false;
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "Ok");
}
}
void Selected()
{
//PositionIdx = 0;
//OnPropertyChanged(nameof(PositionIdx));
//FilterSnagList();
Refresh();
}
void FilterSnagList()
{
var allJobs = SnagListAppXs;
if (staffId != 0) allJobs = allJobs.Where(x => x.StaffId == staffId).ToList();
if (updateProperty) OnPropertyChanged(nameof(SnagListPriorities));
if (selectedIndex > 0) allJobs = allJobs.Where(sli => sli.Priority == selectedIndex).ToList();
SnagListPriorities.SnagListApps.Clear();
//SnagListPriorities.SnagListApps = new ObservableRangeCollection<SnagListAppX>(allJobs);
SnagListPriorities.SnagListApps.AddRange(allJobs);
//OnPropertyChanged(nameof(SnagListPriorities.SnagListApps));
updateProperty = false;
}
void ShowModalMyJobs()
{
staffId = myJobsEnabled ? int.Parse(Settings.StaffIdSetting) : 0;
MyJobsTitle = myJobsEnabled ? "All Jobs" : "My Jobs";
AcceptToolBar = !myJobsEnabled;
myJobsEnabled = !myJobsEnabled;
SelectedIndex = 0;
updateProperty = true;
}
void Refresh()
{
IsBusy = true;
var allJobs = SnagListAppXs.Where(s => s.StaffId == 115);
SnagListPriorities.SnagListApps.Clear();
SnagListPriorities.SnagListApps.AddRange(allJobs);
IsBusy = false;
}
}
}
looks a bit messy, but wanted to show, that I tried already a lot of things.
Last try was a simple RefreshView.
It works as long as the itemsSource is not changing. Once it changes and the first card is not shown, it crashes.
Any ideas? Many thanks
I have a question here, however the problem is not solved perfectly. I posted another question for more clarity.
I'm trying to upload an image through the API. As in the code below, I have an image selector button, the list shows the selected images. And 1 button to post the image.
I have a list of pictures:
<Grid x:Name="pickimg" Grid.Row="0" Grid.Column="1" HorizontalOptions="End" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Image Margin="0">
<Image.Source>
<FontImageSource Color="#ddd" Size="22" FontFamily="MaterIcon" Glyph="{x:Static local:FontIconsClass.Camera}"/>
</Image.Source>
</Image>
</StackLayout>
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="pickimg_Tapped" />
</Grid.GestureRecognizers>
</Grid>
<StackLayout x:Name="listImg" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame HasShadow="False" Padding="0" IsClippedToBounds="True" CornerRadius="4">
<Image HeightRequest="70" WidthRequest="70" Aspect="AspectFill" Source="{Binding .}"/>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<Button x:Name="bt_addfeed" Clicked="bt_addfeed_Clicked" CornerRadius="7" FontSize="13" Text="Post" HorizontalOptions="Fill"/>
.xaml.cs
List<ImageSource> imgList = new List<ImageSource>();
async void pickimg_Tapped(System.Object sender, EventArgs e)
{
var pickResult = await MediaGallery.PickAsync(5, MediaFileType.Image);
if(pickResult?.Files == null)
{
return;
}
else
{
//var imgList = new List<ImageSource>();
foreach (var img in pickResult?.Files)
{
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
}
}
private async void bt_addfeed_Clicked(object sender, EventArgs e)
{
var getResult = imgList;
if (getResult == null)
{
return;
}
else
{
foreach(var img in getResult)
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await img.OpenReadAsync()), "file", img.FileName);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("xxxx/api/UploadFileFeeds", content);
}
}
}
How img.FileName? and img.OpenReadAsync()?
Please help, thanks
create two lists
List<ImageSource> imgList = new List<ImageSource>();
List<FileResult> fileList = new List<FileResult>();
then populate both of them
foreach (var img in pickResult?.Files)
{
fileList.Add(img);
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
then when you need to transfer the files, use fileList
foreach(var img in fileList)
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await img.OpenReadAsync()), "file", img.FileName);
var httpClient = new HttpClient();
var responses = await httpClient.PostAsync("https://v1api.venuskorea.com.vn/api/UploadFileFeeds", content);
}
This is my code in my edit.cs
var db = new SQLiteConnection(_dbPath);
StackLayout stackLayout = new StackLayout();
_listView = new ListView();
_listView.ItemsSource = db.Table<SpeechRecTable>().OrderBy(x => x.Text).ToList();
_listView.ItemSelected += _listView_ItemSelected;
//_listView.SeparatorColor = Color.WhiteSmoke;
stackLayout.Children.Add(_listView);
_button = new Button();
_button.Text = "UPDATE";
_button.BackgroundColor = Color.Coral;
_button.TextColor = Color.WhiteSmoke;
_button.Clicked += _button_Clicked;
stackLayout.Children.Add(_button);
Content = stackLayout;
I am new in xamarin, and Im trying to create a CRUD application, I am following this tutorial: https://www.youtube.com/watch?v=aabHAgY5VXo&t=58s
I cant seem to customize its font size, this is just a .cs file, not a xaml.cs file
I show you 2 solution.
In C#
public class CustomCell : ViewCell
{
public CustomCell()
{
var nameLabel = new Label();
var verticaLayout = new StackLayout();
var horizontalLayout = new StackLayout();
//set bindings
nameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
nameLabel.FontSize = 24;
//add views to the view hierarchy
verticaLayout.Children.Add(nameLabel);
horizontalLayout.Children.Add(verticaLayout);
// add to parent view
View = horizontalLayout;
}
}
_listView.ItemTemplate = new DataTemplate(typeof(CustomCell));
or in Xaml
<StackLayout>
<ListView x:Name="ItemsListView"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>First Item</x:String>
<x:String>Second Item</x:String>
<x:String>Third Item</x:String>
<x:String>Fourth Item</x:String>
<x:String>Fifth Item</x:String>
<x:String>Sixth Item</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item descripton"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Try modifying your code like this,
var db = new SQLiteConnection(_dbPath);
StackLayout stackLayout = new StackLayout();
ListView _listView = new ListView
{
// template for displaying each item.
ItemTemplate = new DataTemplate(() =>
{
Label nameLabel = new Label();
nameLabel.TextColor = Color.Black;
nameLabel.FontSize = 15;
nameLabel.SetBinding(Label.TextProperty, "Name");
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(5),
VerticalOptions = LayoutOptions.Center,
Children =
{
nameLabel
}
}
};
})
};
//_listView.SeparatorColor = Color.WhiteSmoke;
_listView.ItemsSource = db.Table<SpeechRecTable>().OrderBy(x => x.Text).ToList();
_listView.ItemSelected += _listView_ItemSelected;
stackLayout.Children.Add(_listView);
_button = new Button();
_button.Text = "UPDATE";
_button.BackgroundColor = Color.Coral;
_button.TextColor = Color.WhiteSmoke;
_button.Clicked += _button_Clicked;
stackLayout.Children.Add(_button);
Content = stackLayout;
I wrote this code to try and show a couple of lines of HTML within a web page:
I have this XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Test"
x:Class="Test.HelpCards"
x:Name="HelpCards"
Title="Help ▹ Cards Tab">
<ContentPage.Content>
<ScrollView>
<StackLayout Spacing="10" Margin="20">
<WebView x:Name="Browser" />
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
public HelpCards()
{
InitializeComponent();
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = #"<html><body>
<h1>ABC</h1>
<p>DEF</p>
</body></html>";
Browser.Source = htmlSource;
}
However when running the code I see only a blank page.
Does anyone have any ideas as to what might be wrong?
Make sure to specify layout-options for WebView.
<ContentPage.Content>
<ScrollView> <!-- ScrollView not needed as WebView has inbuilt scrolling behavior -->
<StackLayout Spacing="10" Margin="20">
<WebView x:Name="Browser" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
</StackLayout>
</ScrollView>
</ContentPage.Content>
Xamarin has updated the label element at some point. The update included a way to display HTML in the label element, by adding TextType="Html" to the element.
Example:
<Label TextType="Html">
<![CDATA[
This is <strong style="color:red">HTML</strong> text.
]]>
</Label>
(Source: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/text/label#display-html)
The webview can be in the ContentPage.Content by itself. No need to wrap it in a ScrollView or StackLayout. This method also doesn't require Horizontal or Vetical Options to be specified as well.
<ContentPage.Content>
<WebView x:Name="Browser" />
</ContentPage.Content>
Try this with the webBrowser
public MainPage()
{
InitializeComponent();
CheckWifiOnStart();
CheckWifiContinously();
}
private void CheckWifiOnStart()
{
var source = new HtmlWebViewSource();
source.BaseUrl = "file://android_asset/";
//CONTROL TO SEE IF USER IS CONNECTED
if (!CrossConnectivity.Current.IsConnected)
{
Browser.Source = "file:///android_asset/index.html";
}
else
{
Browser.Source = "ONLINE URL";
}
}
private void CheckWifiContinously()
{
var source = new HtmlWebViewSource();
source.BaseUrl = "file://android_asset/";
//CONTROL TO CONNECTIVITY CHANGE
CrossConnectivity.Current.ConnectivityChanged += (sender, args) => {
if (!CrossConnectivity.Current.IsConnected)
{
DisplayAlert("ERROR", "OFFLINE MODE", "OK");
Browser.Source = "file:///android_asset/index.html";
}
else
{
DisplayAlert("INTERNET DETECTED", "ONLINE MODE", "OK");
Browser.Source = "ONLINE URL";
}
};
}
public interface IBaseUrl { string GetFile(); }
I have a MDPage which is a MasterDetailPage which calls side menu items list page as Master. The Detail for this is added with a new NavigationPage of a home page.
My code is
public MDPage(){
Master = new SideMenuPage();
InitializeComponent();
masterPage.ListView.ItemSelected += OnItemSelected;
Detail = new NavigationPage(new HomePage())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};}
I have a requirement where the NavigationPage contains a bottom menu such that on clicking a bottom menu, the MDPage needs to be reinitialized to set a new NavigationPage of a different page (say AboutUs page). So i added a parameterized constructor for MDPage and on clicking the bottom menu item i am calling App.Current.MainPage = new MDPage("AboutUs").Below is the parameterized constructor.
public MDPage(string bottomMenuItem)
{
Master = new SideMenuPage();
InitializeComponent();
masterPage.ListView.ItemSelected += OnItemSelected;
if("AboutUs" == bottomMenuItem)
{
Detail = new NavigationPage(new AboutUs())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}}
Here the MDPage constructor is called initially when i open the app. Then from the side menu i have the option to open a HomePage which is added as Detail. Note that this HomePage contains a bottom sub menu, which is nothing but an image. On tapping this, it should again reinitialize the MDPage. Here this is working fine in Andorid. But in iOS, it is throwing null exception. It is not allowing me to set Master = new SideMenuPage(); I have found the root cause by trial and error as this code will not throw exception and it is throwing in the iOS Main.cs file. Please help me.
MainPage - XAML
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ClubApp.Views;assembly=ClubApp"
x:Class="ClubApp.Views.MainPage">
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
MainPage.xaml.cs
using System.Linq;using System.Text;using System.Threading.Tasks;using Xamarin.Forms;namespace Test.Views{
public partial class MainPage : MasterDetailPage
{
public MainPage()
{
Master = new MasterPage();
InitializeComponent();
masterPage.ListView.ItemSelected += OnItemSelected;
Detail = new NavigationPage(new Views.HomePage())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
public MainPage(string bottomMenu)
{
Master = new MasterPage();
InitializeComponent();
masterPage.ListView.ItemSelected += OnItemSelected;
if ("News" == bottomMenu)
{
Detail = new NavigationPage(new Views.HomePage())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
else if ("Profile" == bottomMenu)
{
Detail = new NavigationPage(new Views.Profile())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
}
async void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
try
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
if (item.Title == "News")
{
Detail = new NavigationPage(new Views.NewsPage())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
if (item.Title == "Home")
{
Detail = new NavigationPage(new Views.HomePage())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
if (item.Title == "Profile")
{
Detail = new NavigationPage(new Views.Profile())
{
BarBackgroundColor = Color.Black,
BarTextColor = Color.White,
};
}
masterPage.ListView.SelectedItem = null;
IsPresented = false;
}
}
catch (Exception ex)
{
}
}
}}
MasterPage.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="Test.Views.MasterPage"> <ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand" BackgroundColor="#10000c" Padding = "0,50,0,0" >
<StackLayout x:Name="slUserProfile" Orientation="Vertical" Spacing = "0"
VerticalOptions="FillAndExpand">
<Image Source="{Binding member_image}" x:Name="imgSideImage"
HorizontalOptions="CenterAndExpand" Aspect="AspectFill" HeightRequest="100"
WidthRequest="100" />
<Label Text="{Binding name}" TextColor="#efa747"
FontSize ="17"
HorizontalOptions="CenterAndExpand"/>
</StackLayout >
<ListView x:Name="lvSideMenu" VerticalOptions="FillAndExpand" SeparatorVisibility="None"
BackgroundColor="Black">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,5,0,0" Orientation="Horizontal">
<Image Source="{Binding IconSource}"/>
<StackLayout Padding = "10,0,0,0">
<local:CustomLabel Text="{Binding Title}" VerticalOptions="CenterAndExpand"
TextColor="#dac6ac" FontSize ="14"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout></ContentPage.Content></ContentPage>
MasterPage.xaml.cs
using Xamarin.Forms;namespace Test.Views{
public partial class MasterPage : ContentPage
{
public ListView ListView { get { return lvSideMenu; } }
public Page Detail { get; set; }
public MasterPage()
{
InitializeComponent();
var masterPageItems = new List<MasterPageItem>();
//Fills side menu items.
masterPageItems.Add(new MasterPageItem
{
Title = "Profile",
IconSource = "profile_sidemenu.png"
});
masterPageItems.Add(new MasterPageItem
{
Title = "Home",
IconSource = "home_smenu.png"
});
masterPageItems.Add(new MasterPageItem
{
Title = "News",
IconSource = "news_smenu.png"
});
lvSideMenu.ItemsSource = masterPageItems;
Icon = "menu.png";
Title = "Menu";
}
}
public class MenuItems
{
public string MenuTitle { get; set; }
}
public class MasterPageItem
{
public string Title { get; set; }
public string IconSource { get; set; }
}}
HomePage.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="Test.Views.HomePage" Title="Home"><ContentPage.Content><StackLayout> <Label Text="This is Home page"/></StackLayout></ContentPage.Content></ContentPage>
Profile.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="Test.Views.Profile" Title="Profile"><ContentPage.Content> <StackLayout>
<StackLayout>
<Label Text="This is Profile page" />
</StackLayout>
<StackLayout HeightRequest="80">
<Grid RowSpacing="0" ColumnSpacing="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout x:Name="tProfile" BackgroundColor="Red" Grid.Column="0" Spacing="0" Padding="0,10,0,10">
<Image Source="bprofileSel.png" HorizontalOptions="Center" VerticalOptions="End"/>
<Label Text="Profile" FontSize="10" TextColor="White" HorizontalOptions="CenterAndExpand" VerticalTextAlignment="Center"/>
</StackLayout>
<StackLayout x:Name="tNews" BackgroundColor="Black" Grid.Column="1" Spacing="0" Padding="0,10,0,10">
<Image Source="bNewsUnsel.png" HorizontalOptions="Center" VerticalOptions="End"/>
<local:CustomLabel Text="News" FontSize="10" TextColor="White" HorizontalOptions="CenterAndExpand" VerticalTextAlignment="Center"/>
</StackLayout>
</Grid>
</StackLayout>
</StackLayout></ContentPage.Content></ContentPage>
Profile.xaml.cs
Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Xamarin.Forms;namespace Test.Views{
public partial class Profile : ContentPage
{
public Profile()
{
InitializeComponent();
try
{
tProfile.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => ProfileClicked()),
});
tNews.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => NewsClicked()),
});
}
catch (Exception ex)
{
}
}
private void ProfileClicked()
{
App.Current.MainPage = new MainPage("Profile");
}
private void NewsClicked()
{
App.Current.MainPage = new MainPage("News");
}
}}
News page can be set similar to the profile page. In app.cs call MainPage = new MainPage()
Here when the app is launched, it will show the HomePage with the side menu. Now when i click a menu (say profile from side menu), it will take me to the profile page and according to the design a bottom submenus can be seen there. Clicking on it will cause the null exception occurring in iOS code. This is working fine in android. My assumption is the root cause is due to MasterPage reinitialization to Master. But i need this requirement to be flown like this. Please help me.
This is the error in iOS Main.cs