System.InvalidOperationException: 'Cannot assign a native control without an Element; - c#

I am working on a project "CoManga" and I wanted to add advertisements in it. Implementing ads on UWP seemed straight forward, like Android and iOS. However, I'm stuck now.
Anyways, I followed this tutorial by James Montemagno and added everything. I even see the test advertisements, which is great. However, when I try to move away from that page (when I press "BACK Button") and go to previous page, I get an error.
This is the error :
Setting up AdControlView in UWP throws System.InvalidOperationException: 'Cannot assign a native control without an Element; Renderer unbound and/or disposed. Please consult Xamarin.Forms renderers for reference implementation of OnElementChanged.'.
It is thrown at line number 50, where I set the SetNativeControl(adView);. I've commented it out right now, but as soon as I un-comment it, I see this error.
Can someone help me out here with this.

Setting up AdControlView in UWP throws System.InvalidOperationException: 'Cannot assign a native control without an Element; Renderer unbound and/or disposed. Please consult Xamarin.Forms renderers for reference implementation of OnElementChanged.
The reason is that xamarin Element has released but SetNativeControl invoked again cause the native control can't find the matched xamarin Element when page going back. So you could set a flag (isRegist) to record the registed ad.
public class AdViewRenderer : ViewRenderer<AdControlView, AdControl>
{
string bannerId = "test";
AdControl adView;
string applicationID = "3f83fe91-d6be-434d-a0ae-7351c5a997f1";
bool isRegist = false;
protected override void OnElementChanged(ElementChangedEventArgs<AdControlView> e)
{
base.OnElementChanged(e);
if (Control == null && isRegist != true)
{
CreateNativeAdControl();
SetNativeControl(adView);
isRegist = true;
}
}
private void CreateNativeAdControl()
{
if (adView != null)
return;
var width = 300;
var height = 50;
if (AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Desktop")
{
width = 728;
height = 90;
}
// Setup your BannerView, review AdSizeCons class for more Ad sizes.
adView = new AdControl
{
ApplicationId = applicationID,
AdUnitId = bannerId,
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Bottom,
Height = height,
Width = width
};
}
}

Related

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.

Notification bar appears all white in light mode

I'm using Template 10 and in Windows 10 Mobile when I choose the light mode, the notifications bar appears all white
and can not see the notifications, the hours, etc.
In the dark mode everything seems fine image:
How do I solve this?
I do this in my hamburger's override for UIElement CreateRootElement() after my database setup/migrations are done.
if(Template10.Utils.DeviceUtils.Current().IsPhone()){
var statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
if(statusBar != null)
{
if(Application.Current.RequestedTheme == ApplicationTheme.Light)
//background && foreground or combination, and dependent on color choices
statusBar.ForegroundColor = Windows.UI.Colors.Black;
else if(Application.Current.RequestedTheme == ApplicationTheme.Dark
statusBar.ForegroundColor = Windows.UI.Colors.White;
}
}
Template10 already has a lot of the logic built in just have to know where it is. As #Jay Zuo said you have to also include the Mobile reference as well..
As #mvermef said, to solve this problem, we can set the color used in status bar according to application's theme. We can get application's theme by using Application.RequestedTheme property and set status bar's color by using properties in Status​Bar Class. For a simple example:
public MainPage()
{
InitializeComponent();
NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
if (ApiInformation.IsTypePresent("Windows.UI.ViewManagement.StatusBar"))
{
var statusBar = StatusBar.GetForCurrentView();
if (statusBar != null)
{
if (Application.Current.RequestedTheme == ApplicationTheme.Light)
{
statusBar.ForegroundColor = Windows.UI.Colors.Black;
}
else if (Application.Current.RequestedTheme == ApplicationTheme.Dark)
{
statusBar.ForegroundColor = Windows.UI.Colors.White;
}
}
}
}
Please note to use Status​Bar Class, we need reference Windows Mobile Extensions for the UWP in the project.

Cocossharp Template not working

I'm new to cocossharp. I installed cocossharp templates for visual studio, when i select a new cocossharp android game, and run the application, all I get is a black screen with a logo at the top. From the code, I believe i am supposed to get a blue screen with a label written
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our game view from the layout resource,
// and attach the view created event to it
CCGameView gameView = (CCGameView)FindViewById(Resource.Id.GameView);
gameView.ViewCreated += LoadGame;
}
void LoadGame(object sender, EventArgs e)
{
CCGameView gameView = sender as CCGameView;
if (gameView != null)
{
var contentSearchPaths = new List<string>() { "Fonts", "Sounds" };
CCSizeI viewSize = gameView.ViewSize;
int width = 1024;
int height = 768;
// Set world dimensions
gameView.DesignResolution = new CCSizeI(width, height);
// Determine whether to use the high or low def versions of our images
// Make sure the default texel to content size ratio is set correctly
// Of course you're free to have a finer set of image resolutions e.g (ld, hd, super-hd)
if (width < viewSize.Width)
{
contentSearchPaths.Add("Images/Hd");
CCSprite.DefaultTexelToContentSizeRatio = 2.0f;
}
else
{
contentSearchPaths.Add("Images/Ld");
CCSprite.DefaultTexelToContentSizeRatio = 1.0f;
}
gameView.ContentManager.SearchPaths = contentSearchPaths;
CCScene gameScene = new CCScene(gameView);
gameScene.AddLayer(new GameLayer());
gameView.RunWithScene(gameScene);
}
}
public class GameLayer : CCLayerColor
{
// Define a label variable
CCLabel label;
public GameLayer() : base(CCColor4B.Blue)
{
// create and initialize a Label
label = new CCLabel("Hello CocosSharp", "Fonts/MarkerFelt", 22, CCLabelFormat.SpriteFont);
// add the label as a child to this Layer
AddChild(label);
}
protected override void AddedToScene()
{
base.AddedToScene();
// Use the bounds to layout the positioning of our drawable assets
var bounds = VisibleBoundsWorldspace;
// position the label on the center of the screen
label.Position = bounds.Center;
// Register for touch events
var touchListener = new CCEventListenerTouchAllAtOnce();
touchListener.OnTouchesEnded = OnTouchesEnded;
AddEventListener(touchListener, this);
}
void OnTouchesEnded(List<CCTouch> touches, CCEvent touchEvent)
{
if (touches.Count > 0)
{
// Perform touch handling here
}
}
}
I put a break point in the method thats called when the event ViewCreated is fired, the breakpoint is never hit. I tried creating the CCGameView first then then registering the eventhandler because I thought the event was firing before registering
CCGameView gameView = new CCGameView(this);
gameView.ViewCreated += LoadGame;
gameView = (CCGameView)FindViewById(Resource.Id.GameView);
then I tried calling the LoadGame method directly
CCGameView gameView = (CCGameView)FindViewById(Resource.Id.GameView);
gameView.ViewCreated += LoadGame;
LoadGame(gameView, EventArgs.Empty);
but this resulted in a null exception for the gameView.ContentManager.
My only other suspicion is the emulator itself, perhaps it needs something installed extra, however for a normal xamarin android project it works perfectly. Iv also tried looking at the various examples on Xamarin but they all use Application Delegate, which if i'm not mistaken, was the old way of doing thing. If anyone can help, Id appreciate it. Thanks
It was an emulator issue, had to check the Use Host GPU option on the emulator. On the Android Virtual Device Manager where I can select my created emulators, I selected an emulator I had created, then instead of starting it, I first Edited it, that's where I found the option (Since I had already created some emulators). The answer is here

Prevent activity from reload after rotation in xamarin, monodroid

Ok... So my problem is to prevent from activity to reload after orientation is changed.
Basically, what I did is this:
[Activity(Label = "migs", ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation)]
This is worked fine, until I changed "Target API" to 14. If I'm changing it back to 12, then everything is working, but on 14, activity is being restarted (OnCreate method is fires after rotation).
So... You'll ask why do I need "Target API" 14? - Easy! Because in my app, I'm playing video, and for that I need "true full screen". All API's below 14 adding "Settings" (three dots) button. In case of HTC, it's big and ugly button, that I was unable to get rid of.
If you know how to do one of the two (Get rid of the "settings" button in API 12, or prevent activity from reload after orientation changed in API 14), I'll be very thank full for your help.
Ok... At last I solved it! :)
Saving activity state instead of preventing activity from reload, from first sight can seem to be a little tricky, but in fact is really easy and it's the best solution for situations like this.
In my case, I had a ListView, that populates from the internet with items, that stored in custom list adapter. If device orientation was changed, the activity was reloaded, so does the ListView, and I was loosing all the data.
All I needed to do is to override the OnRetainNonConfigurationInstance method.
Here's a quick sample of how to do it.
First of all, we need a class, that can handle all of our stuff.
Here is a wrapper for all the things we need to save:
public class MainListAdapterWrapper : Java.Lang.Object
{
public Android.Widget.IListAdapter Adapter { get; set; }
public int Position { get; set; }
public List<YourObject> Items { get; set; }
}
In our activity, we need to hold variables, to store all the data:
ListView _listView; //Our ListView
List<YourObject> _yourObjectList; //Our items collection
MainListAdapterWrapper _listBackup; //The instance of the saving state wrapper
MainListAdapter _mListAdapter; //Adapter itself
Then, we overriding the OnRetainNonConfigurationInstance method in the activity:
public override Java.Lang.Object OnRetainNonConfigurationInstance()
{
base.OnRetainNonConfigurationInstance();
var adapterWrapper = new MainListAdapterWrapper();
adapterWrapper.Position = this._mListAdapter.CurrentPosition; //I'll explain later from where this came from
adapterWrapper.Adapter = this._listView.Adapter;
adapterWrapper.Items = this._yourObjectList;
return adapterWrapper;
}
And the final stage is to load saved state in OnCreate method:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.list);
this._listView = FindViewById<ListView>(Resource.Id.listView);
if (LastNonConfigurationInstance != null)
{
this._listBackup = LastNonConfigurationInstance as MainListAdapterWrapper;
this._yourObjectList = this._listBackup.Items;
this._mListAdapter = this._listBackup.Adapter as MainListAdapter;
this._listView.Adapter = this._mListAdapter;
//Scrolling to the last position
if(this._listBackup.Position > 0)
this._listView.SetSelection(this._listBackup.Position);
}
else
{
this._listBackup = new MainListAdapterWrapper();
//Here is the regular loading routine
}
}
And about the this._mListAdapter.CurrentPosition... In my MainListAdapter, I added this property:
public int CurrentPosition { get; set; }
And the, in the `GetView' method, I did that:
this.CurrentPosition = position - 2;
P.S.
You don't have to implement exactly as I showed here. In this code, I'm holding a lot of variables, and making all the routine inside the OnCreate method - that is wrong. I did that, just to show how it can be implemented.
what happen when orientation change (consider you enable rotation in your phone) ?
Android restart activity onDestroy() is called, followed by onCreate() , you can distinguish between onDestroy() call to kill activity or restart app throw old answer.
Prevent Activity restart
just set ConfigurationChanges to both Orientation , ScreenSize
[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
why this may be not working ?
I dont think this will not working but set RetaintInstance to true read more about RetainInstance
class myFragment: Fragment
{
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.RetainInstance = true;
// this to change screen orientation
Activity.RequestedOrientation = ScreenOrientation.Landscape;
}
.....
}
hope this help
Above API 13, you need to include screensize in your ConfigChanges.
As denoted here.
Maybe adding that tag to your activity for API13+ will help?

WP7/8 changing InputScope dynamically after an event using C#

I'm making an app for Windows Phone, I've been trying for ages to get the InputScope of the main text box to change when the orientation is changed to landscape (so that the keyboard takes up less space in landscape without the autocorrect bar), and back again.
I experimented with a second text box and hiding the others upon an orientation change, but this did not work neatly. :P
Try as I might I can't get this to work and can find no way to change the InputScope value after the OrientationChangedEvent argument, which has worked nicely in changing the position of the elements of the page around orientations.
I'm still fairly new to developing apps with C# and XAML, and I hope there's a nice easy way to set the InputScope of my text box that one of you awesome people could show me!
-EDIT : Here's the event handler, everything inside there works absolutely fine, but any way I try to add anything to do with InputScope does not work :(
private void MainPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if ((e.Orientation & PageOrientation.Portrait) == (PageOrientation.Portrait))
{
//Portrait
PlaceholderText.FontSize = 29.333;
PlaceholderText.Padding = new Thickness (0,0,0,0);
MainTweet.FontSize = 29.333;
MainTweet.Padding = new Thickness (12,8,12,8);
Counter.Margin = new Thickness (0,212,28,0);
}
else
{
//Landscape
PlaceholderText.FontSize = 23;
PlaceholderText.Padding = new Thickness (8,0,0,0);
MainTweet.FontSize = 22;
MainTweet.Padding = new Thickness (16,8,180,0);
Counter.Margin = new Thickness (0,-18,28,0);
}
}
MainTweet.Text is the textbox that the keyboard is focusing on by default, when the page is changed to landscape I'd love to be able to change this from the "Search" InputScope to another, probably "URL". The stuff currently in there rearranges elements on the page nicely when the orientation is changed, I appreciate it might not look that neat...
There are multiple "orientation" states in the enumeration - not just Portrait and Landscape. The following worked for me to change the scope (on Windows Phone 7.5 emulator):
if (e.Orientation == PageOrientation.Landscape
|| e.Orientation == PageOrientation.LandscapeRight
|| e.Orientation == PageOrientation.LandscapeLeft)
{
InputScope inputScope = new InputScope();
InputScopeName inputScopeName = new InputScopeName();
inputScopeName.NameValue= InputScopeNameValue.Url;
inputScope.Names.Add(inputScopeName);
textBox1.InputScope = inputScope;
}
So you'd drop that into your MainPage_OrientationChanged event handler.

Categories