Convert Xamarin.Forms StackLayout to Android View - c#

I am trying to convert Xamarin.Forms stack layout to Android native View class to use it in IWindowManager.AddView method.
Conversion code is
static class ViewToAndroidViewConverter
{
public static Android.Views.View GetNativeView(this VisualElement view)
{
if (Platform.GetRenderer(view) == null)
Platform.SetRenderer(view, Platform.CreateRenderer(view));
var renderer = Platform.GetRenderer(view);
renderer.Tracker.UpdateLayout();
return renderer.ViewGroup;
}
}
And this is StackLayout that I am trying to convert
StackLayout testView = new StackLayout();
testView.Children.Add(new Label { Text = "Incoming call text" });
testView.Children.Add(new Label { Text = incomingNumber });
testView.BackgroundColor = Color.Green;
windowManager.AddView( testView.GetNativeView(),
new WindowManagerLayoutParams {
Title = "Call title sample",
Gravity = GravityFlags.Center,
Type = WindowManagerTypes.SystemAlert,
Height = 500,
Width = 1080
});
The problem is that this test view is shown, but without label contents (solid green rectangle only).
Is there any way to create an android native view from stack layout with full contents?

Related

Image from ImageSource

I tried to follow the following example by #CraigDunn with the sample code
someButton.Image = ImageSource.FromFile("imageName.png");
My own try looks like this:
_NavBarPrevPage = new Button
{
Image = ImageSource.FromResource("media_step_back.png")),
BackgroundColor = Color.Red,
TextColor = Color.White,
};
For me, the IDE tells me:
The type Xamarin.Forms.ImageSource can't be converted to Xamarin.Forms.FileImageSource. An explicit conversion exists. Perhaps a conversion is missing.
I think I'm doing exactely what #CraigDunn proposed.
What am I doing wrong?
I've tried the following, and I was able to get rid of the conversion errors in the current answer, but the image is not shown on the button, while it is shown in an image, so the file name is correct:
var nImg = new FileImageSource()
{
File = "media_step_back.png",
};
_NavBarPrevPage = new Button
{
Image =nImg,
};
If the thing you need is a button with image that is implementing by code-behind :
Button button = new Button
{
BackgroundColor = Color.Red,
Font = Font.Default,
FontSize = 10,
TextColor = Color.White,
HeightRequest = 35,
WidthRequest = 80
};
button.Image = "media_step_back.png";
this.Content = button;
Please remember to put the image file (media_step_back.png) in your target platform's resource folder
UPDATE:
You problem were you didn't add the image source in the Property folder and target platform's resource folder (Please note that in below example, I have added a xamarin.png image in each Xamarin "Property" folder, Android's "Resource" and iOS's "Resource" folder)
Below is the updated code that I placed the button into a StackLayout (which also able to works if without StackLayout) :
public class MainPageNew : ContentPage
{
public MainPageNew()
{
StackLayout parent = new StackLayout();
Button button = new Button
{
BackgroundColor = Color.Red,
Font = Font.Default,
FontSize = 10,
TextColor = Color.White,
HeightRequest = 300,
WidthRequest = 80
};
//button.Image = "media_step_back.png";
button.Image = "xamarin.png";
parent.Children.Add(button);
this.Content = parent;
}
Android
iOS:
This is the download link of the updated code.

Xamarin C# content page not loading image for Android JVM

I have a problem attempting to load an image for the Android JVM in use on Visual Studio 2017 when debugging. Below is a sample of my code:
public class ImageDisplayPage : ContentPage
{
public ImageDisplayPage()
{
Content = new ScrollView
{
Content = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children =
{
new Image
{
IsVisible = true,
Aspect = Aspect.AspectFit,
Source = ImageSource.FromResource("Resources.a.png")
}
}
}
};
}
}
I have a folder in my project called "Resources" where the image is supposed to be loaded from, and have followed the path convention used in numerous posts on StackOverFlow and the guide listed here: https://developer.xamarin.com/guides/xamarin-forms/user-interface/images
I use Visual Studio 2017, coding in C# and when I attempt to debug this, the following message is what I get from the debug output:
Image data was invalid: Xamarin.Forms.StreamImageSource
The image in question is an 80kb PNG image.
Thank you in advance for any assistance
You should place your image inside the Resources/drawable folder of your android project and only place the image name and the extension.
public class ImageDisplayPage : ContentPage
{
public ImageDisplayPage()
{
Content = new ScrollView
{
Content = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children =
{
new Image
{
IsVisible = true,
Aspect = Aspect.AspectFit,
Source = "a.png"
}
}
}
};
}
}

Xamarin.Forms UWP - Print Webview with pagination support

I'm working on Xamarin.Forms based project, trying to print the webview content with pagination.
I've referred the following link already:
How do I print WebView content in a Windows Store App?
But unfortunately this way is not working with Xamarin.Forms because the way demonstrated in the above link is by filling the rectangle(windows shape) using webviewbrush (both the rectangle and webviewbrush are platform dependent controls to UWP). The problem is we can't use webviewbrush to draw rectangle(Xamarin Forms shape).
As a workaround I did the following:
created a boxview in xamarin forms PCL project
created a renderer for this boxview in UWP project(this will give us the windows rectangle shape) and then I did put this rectangle shape into one of the public static properties in PCL project's App.cs class to make it available for Webviewrenderer.cs class for filling this rectangle with webviewbrush.
I can able to access it from webviewrenderer.cs class from UWP project but the problem is the printer dialog shows an empty page.
Pagination works just fine as demonstrated in the above stack overflow link, but all pages are being empty.
Apparently the problem would be with rectangle. Because the same logic is just works fine if I create a native UWP project and the printer dialog shows the webpage as well.
Any help would be much appreciated.
Thanks in advance!
Pagination works just fine as demonstrated in the above stack overflow link, but all pages are being empty.
I have realized the basic printing feature according to your process. I placed the GetWebViewBrush method in the webviewrenderer. Unfortunately, the same issue occur in my side.
async Task<WebViewBrush> GetWebViewBrush(Windows.UI.Xaml.Controls.WebView webView)
{
// resize width to content
var _OriginalWidth = webView.Width;
var _WidthString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollWidth.toString()" });
int _ContentWidth;
if (!int.TryParse(_WidthString, out _ContentWidth))
throw new Exception(string.Format("failure/width:{0}", _WidthString));
webView.Width = _ContentWidth;
// resize height to content
var _OriginalHeight = webView.Height;
var _HeightString = await webView.InvokeScriptAsync("eval",
new[] { "document.body.scrollHeight.toString()" });
int _ContentHeight;
if (!int.TryParse(_HeightString, out _ContentHeight))
throw new Exception(string.Format("failure/height:{0}", _HeightString));
webView.Height = _ContentHeight;
// create brush
var _OriginalVisibilty = webView.Visibility;
webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
var _Brush = new WebViewBrush
{
Stretch = Stretch.Uniform,
SourceName = webView.Name
};
// _Brush.SetSource(webView);
_Brush.Redraw();
// reset, return
webView.Width = _OriginalWidth;
webView.Height = _OriginalHeight;
webView.Visibility = _OriginalVisibilty;
return _Brush;
}
When I was debuging, I found webView.Name has never been set value, So I make a new Name property for the customWebView.
public static readonly BindableProperty NameProperty = BindableProperty.Create(
propertyName: "Name",
returnType: typeof(string),
declaringType: typeof(MyWebView),
defaultValue: default(string));
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
And set the Name property of native control(Windows.UI.Xaml.Controls.WebView) with the following code in OnElementChanged method.
if (e.NewElement != null)
{
Control.Name = (Element as MyWebView).Name;
Control.NavigationCompleted += Control_NavigationCompleted;
}
Surprisingly, the page is no longer empty.

Changing Xamarin Label in ListCell does not work

I have a problem with a ListView. I want each Cell to have a label and a switch but the text of the label does not appear.
Here is my code:
public class FilterPage : ContentPage
{
public FilterPage()
{
List<FilterCell> listContent = new List<FilterCell>();
foreach(string type in Database.RestaurantTypes)
{
FilterCell fc = new FilterCell();
fc.Text = type;
listContent.Add(fc);
}
ListView types = new ListView();
types.ItemTemplate = new DataTemplate(typeof(FilterCell));
types.ItemsSource = listContent;
var layout = new StackLayout();
layout.Children.Add(types);
Content = layout;
}
}
public class FilterCell : ViewCell
{
private Label label;
public Switch CellSwitch { get; private set; }
public String Text{ get { return label.Text; } set { label.Text = value; } }
public FilterCell()
{
label = new Label();
CellSwitch = new Switch();
var layout = new StackLayout
{
Padding = new Thickness(20, 0, 0, 0),
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = { label, CellSwitch }
};
View = layout;
}
}
If I enter a fixed Text in the FilterCell-Constructor it works fine (e.g.: label.Text = "Hello World")
When I create a Method for the ItemSelected-Event and read out the SelectedItem.Text Property I get the text I assigned as Value but it's never displayed. Only the switch is displayed when I try to run this Code.
Thanks for your help
Niko
Ohh boy. This code looks like a rape (sorry I had to say this).
Now let's see what's wrong:
The reason is you are mixing up data and view heavily.
The line
types.ItemTemplate = new DataTemplate(typeof(FilterCell));
means: "For each item in the list (ItemsSource) create a new filter cell". The FilterCells that you create in the loop are never displayed.
The easy fix
public class FilterPage : ContentPage
{
public FilterPage()
{
var restaurantTypes = new[] {"Pizza", "China", "German"}; // Database.RestaurantTypes
ListView types = new ListView();
types.ItemTemplate = new DataTemplate(() =>
{
var cell = new SwitchCell();
cell.SetBinding(SwitchCell.TextProperty, ".");
return cell;
});
types.ItemsSource = restaurantTypes;
Content = types;
}
}
There is a standard cell type that contains a label and a switch SwitchCell, use it.
As ItemsSource of your list, you have to use your data. In your case the list of restaurant types. I just mocked them with a static list.
The DataTemplate creates the SwitchCell and sets the Databinding for the Text property. This is the magic glue between View and data. The "." binds it to the data item itself. We use it, because our list contains items of strings and the Text should be exactly the string. (read about Databinding: https://developer.xamarin.com/guides/xamarin-forms/getting-started/introduction-to-xamarin-forms/#Data_Binding )
I striped away the StackLayout that contained the list. You can directly set the list as Content of the page.
Lesson
use standard controls, if possible
You should always try to remember to keep data and view apart from each other and use data binding to connect to each other.
Try to avoid unnecessary views.

How to Remove a Xamarin.Forms TableView and Re-Create It Without Application Crashing

I have a StackLayout in Xamarin.Forms 1.4.2, and from code-behind I am trying to create a table view, and then just for a test I have a button to re-create the TableView in the StackLayout.
If I use the following, that uses a standard TextCell, then I can re-create the TableView as many times as I wish without the application crashing:-
This is on Windows Phone btw:-
TableView tableView1 = new TableView()
{
Intent = TableIntent.Form,
VerticalOptions = LayoutOptions.FillAndExpand
};
myStackLayoutControl.Children.Add(tableView1);
tableView1 = new TableRoot()
{
new TableSection("Section 1")
{
new TextCell()
{
Text = "Text1",
Detail = "Text2"
}
}
};
However when I change the TextCell to a ViewCell such as:-
new ViewCell()
{
View = new Label()
{
Text="hello",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
},
Height = 100
}
It will display the TableView correctly on the first execution.
However clicking a button that clears down the TableView and executes the same code to re-create it will run the same code, however straight after it has finished the function it will crash the entire application with an Application_UnhandledException being caught!
The exception caught is:-
MeasureOverride of element 'Xamarin.Forms.Platform.WinPhone.ViewToRendererConverter+WrapperControl' should not return PositiveInfinity or Nan as its DesiredSize.
Does anyone have any ideas how to resolve this?

Categories