Xamarin.Forms targeting macOS - macos

I am using Visual Studio for Mac 7.6.6 to create a Xamarin.Forms app targeting macOS (to be shared with something running on Windows). I create a new Project and select
Multiplatform App | Blank Forms App. Click Next
Configure your Blank Forms App. There are target platforms: Android and iOS.
(There is nothing for macOS). Since I have not installed the build toolkits for either iOS and android, both of these checkboxes are disabled. Therefore the Next button on this wizard page is disabled.
How do I proceed? I assume there is no way to use the New Project wizard for this.
I came across an old post for starting with a Xamarin Cocoa app and using NuGet to put the Xamarin Forms functionality but don't understand the code
LoadApplication(new App()); // <-- don't know what App is
I suspect the VS Mac and Xamarin.Forms are out of sync being on the bleeding edge. Has anyone gotten this to work?

I would suggest following SushiHangover's suggestion since that is simpler which is what you have done already:
Add a new CocoaApp project to your solution.
Install Xamarin.Forms NuGet package into your CocoaApp.
Reference the shared project or .NET Standard project from your CocoaApp project.
Edit info.plist and remove the source entry (NSMainStoryboardFile).
Change the AppDelegate to derive from Xamarin.Forms.Platform.MacOS.FormsApplicationDelegate.
Update Main.cs to initialize the AppDelegate
In the AppDelegate's DidFinishLaunching add the code to initialize Xamarin.Forms.
Create a new NSWindow which should be returned from the MainWindow property in the AppDelegate.
Main.cs:
static class MainClass
{
static void Main(string[] args)
{
NSApplication.Init();
NSApplication.SharedApplication.Delegate = new AppDelegate();
NSApplication.Main(args);
}
}
AppDelegate.cs:
[Register("AppDelegate")]
public class AppDelegate : Xamarin.Forms.Platform.MacOS.FormsApplicationDelegate
{
NSWindow window;
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
var rect = new CoreGraphics.CGRect(200, 1000, 1024, 768);
window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.Title = "Xamarin.Forms on Mac!";
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
public override NSWindow MainWindow
{
get { return window; }
}
public override void DidFinishLaunching(NSNotification notification)
{
Xamarin.Forms.Forms.Init();
LoadApplication(new App());
base.DidFinishLaunching(notification);
}
public override void WillTerminate(NSNotification notification)
{
// Insert code here to tear down your application
}
}
However Visual Studio for Mac does include a Mac project with the Xamarin.Forms project templates. However it does not expose this in the New Project dialog currently. You can create a Mac Forms project from this template but it is a bit more work than what SushiHangover suggested and you have used.
Install the Xamarin.Forms project template into the .NET Core project templates
dotnet new --install "/Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/AddIns/Xamarin.Forms.Addin/Templates/Xamarin.Templates.Multiplatform.0.0.1.nupkg"
Create a new Forms project including the Mac project (you may want to review and set other template parameters - the following creates a blank Forms app with Android, iOS, Mac, UWP and a Shared project).
dotnet new forms-app --CreateMacProject -k blank
Create a new blank solution (Other - Miscellaneous - Blank Solution) in the parent directory of the projects you just created.
Add all those projects created to the solution.
Then you can build and run the Mac project which includes Xamarin.Forms.
Note you may want to remove the Xamarin.Forms project template from the .NET Core project templates which you can do by running the following:
dotnet new --debug:reinit

In addition to the approved answer, which is incomplete with recent updates, now you have to do one more step.
Link the delagate in the Mac project main class
main.cs:
static class MainClass
{
static void Main(string[] args)
{
NSApplication.Init();
NSApplication.SharedApplication.Delegate = new AppDelegate();
NSApplication.Main(args);
}
}
nota. My edit was refused and I'm not allowed to add comments. So I added a complementary answer to help those looking for help now.

Related

How to set property for Xamarin.ios view in Rider? (How to update autogenerated View.designer.cs?)

If I am using Visual Studio for Mac it has this field in the designer.
It creates a property in the View.cs file that allows me to bind to it.
I found a similar section in xcode (that is what rider opens up) and it only has these options. No field for Name.
This name field is not what shows up on the button label. I know how to set that.
I would much rather use Rider than Visual Studio for mac. If I have to constantly jump back and forth this would obviously be a problem.
EDIT: From what I can tell, it seems to edit the View.designer.cs.
It has this comment though. How would I be able to edit this from Rider?
// WARNING
//
// This file has been generated automatically by Visual Studio from the
outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
This was what it looks like on default with a new MvvmCross project
using Foundation;
using System;
using System.CodeDom.Compiler;
namespace HelloCrossPlatform.iOS.Views
{
[Register ("FirstView")]
partial class FirstView
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel Label { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITextField TextField { get; set; }
void ReleaseDesignerOutlets ()
{
if (Label != null) {
Label.Dispose ();
Label = null;
}
if (TextField != null) {
TextField.Dispose ();
TextField = null;
}
}
}
}
Here is what it looks like when I add the name property to the button in Visual Studio for Mac with the Designer
using Foundation;
using System;
using System.CodeDom.Compiler;
namespace HelloCrossPlatform.iOS.Views
{
[Register ("FirstView")]
partial class FirstView
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UILabel Label { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIButton SayHelloButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UITextField TextField { get; set; }
[Action ("UIButtonDZD114An_TouchUpInside:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void UIButtonDZD114An_TouchUpInside (UIKit.UIButton
sender);
void ReleaseDesignerOutlets ()
{
if (Label != null) {
Label.Dispose ();
Label = null;
}
if (SayHelloButton != null) {
SayHelloButton.Dispose ();
SayHelloButton = null;
}
if (TextField != null) {
TextField.Dispose ();
TextField = null;
}
}
}
}
Is rider even a good tool to use with Xamarin? I'm getting disappointed they even market it as an option. Really questioning my subscription to JetBrains.. Vscode seems to work just as well as Webstorm which is the only other product I work with from them.
Rider does NOT have a special designer for .xib and .storyboard UI files. We (the Rider team) think we will not be able to implement as good (and actual) UI designer as the native xcode is. So the main scenario to work with Xamarin macios UI in Rider - use xcode interface builder.
You can check the apple documentation about outlets generating:
https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ConnectingObjectstoCode.html
This is a brief description how to do it in xcode 11 with default settings.
Split UI editor into designer and source parts
Ctrl+Click the control you want to bind and drag it into the code. Important note: use .h files to create new actions and outlets, Rider analyzes .h files to build a public API model.
Now you can enter the name of the control it the binding will be created. You will see corresponding outlets in objc code.
Maybe it is not that straightforward so I will try to explain how it works internally.
Xamarin macios project is an (almost) regular .NET C# project. So to allow you edit UI in the xcode, Rider (and VS actually) do some magic. It takes the .NET project and:
Creates the corresponding xcodeproj (pbxproj and friends) project in obj\xcode folder with specific settings and configurations.
Copies all content like views, plist files, images and so on.
Looks for all ViewController types. For each of them Rider generates objc class with actions and outlets.
Opens xcode and the generated project into.
When you have made some changes in that generated project and go back to Rider, it tries to apply all changes:
Copies all changed content files back into .NET project
Updates settings
Parses objc files and regenerate *.designer.cs files for view controllers. For all these files you will see this generated header (can be changed in the future):
// WARNING
//
// This file has been generated automatically by Rider IDE
// to store outlets and actions made in Xcode.
// If it is removed, they will be lost.
// Manual changes to this file may not be handled correctly.
//
To control xcode synchronization process and see whats going on and see what errors occur you can use a special Rider toolwindow: xcode console. It is shown each time you open a project in xcode:
Instead of conclusion: Rider's team tries to provide good experience for Xamarin Developers, even better then VS for Mac. So are working on support some Xamarin parts (Xamarin Forms Hot Reload in the 2020.1) so feel free to share your troubles in our public issue tracker:
https://youtrack.jetbrains.com/issues/RIDER?q=Technology:%20Xamarin%20

How to use a differente theme for a specific page in Xamarin Forms?

I have a default theme for my app. I customize this theme using Style file in Android. But I'm creating a login page that I want use other theme just for it. How can I do that?
I am not sure you can do that, because Android theme can be applied to an activity in Android, but Xamarin.Forms run "within" a single activity, so you would have to do the styling either in Xamarin.Forms. Check out this post on Xamarin Forums where the developer was able to change the theme at runtime, which however restarted the activity and in turn also his Xamarin.Forms app.
If your Xamarin Forms app is only using one activity, then this is quite straightforward. This solution is for Lollipop and versions after. You can do this using platform specific Android code:
public class StatusBarStyleManager : IStatusBarStyleManager
{
public void SetStatusBarColor(Android.Graphics.Color color)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
Device.BeginInvokeOnMainThread(() =>
{
var currentWindow = GetCurrentWindow();
currentWindow.DecorView.SystemUiVisibility = (StatusBarVisibility)SystemUiFlags.LightStatusBar;
currentWindow.SetStatusBarColor(color);
});
}
}
Window GetCurrentWindow()
{
//Note this is a nuget package for retrieving the activity.
var window = CrossCurrentActivity.Current.Activity.Window;
// clear FLAG_TRANSLUCENT_STATUS flag:
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
return window;
}
}
Then just use this implementation in your pages to set their specific status bar colors when they appear.
Inspired by this article when I needed this in my own projects:
https://evgenyzborovsky.com/2018/08/20/dynamically-changing-the-status-bar-appearance-in-xamarin-forms/

Null exception namespace App in Xamarin for UWP

I am developing UWP app in xamarin. The application works on IOS, Mac , Android, Windows. I have created UWP project in it according to the tutorial given in developer.xamarin.com. But it giving error saying Accessibility.App namespace not found.
Here is my code:
namespace Accessibility.UWP
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
this.LoadApplication(new Accessibility.App());
}
}
}
According to your description, the app can't see Accessibility.App. As you claim that Android and iOS projects work there are two things that can cause the problem:
you don't have the reference to your Shared/PCL project in your UWP project (most likely).
you have possibly changed the namespace / class name in the Shared/PCL project to something else than Accessibility.App
This is usually caused by missing reference to the shared project or class library where Xamarin.Forms App class resides. From the description this project should be called Accessibility.
Right-click the UWP project select Add, Reference... then in Solution tab select the Accessibility project.
Also it might happen that the UWP project didn't pick up on the reference, so restarting Visual Studio might help as well.
If all fails, you can try to use class name binding with using. On top of the source code file add:
using FormsApp = Accessibility.App;
And then in code use:
this.LoadApplication(new FormsApp());

xamarin android uitest theme style conflicts

Recently I asked a question over trying to get my theme recognized within the android test project: Unit testing a Xamarin Forms Android specific code project
I'm not running into a conflict that shows up within xunit / nunit as the testing strategy. I feel like it's because the FormsAppCompatActivity with an older activity type, but I'm new to Xamarin and am unsure on how to approach this.
I get a lot of these type of errors:
Attribute "layout_anchorGravity" already defined with incompatible format.
The full list of the similar Attribute errors is:
fabSize
tabMode
expandedTitleGravity
layout_scollFlags
layout_collapseMode
collapsedTitleGravity
tabGravity
showDividers
displayOptions
showAsActions
actionBarSize
finally I have the addition error:
Found tag styles where item is expected
//Within the Android Forms project, I have this inheritance:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity {
// typical code
}
//within the Android UITest project
public class MainActivity : Xunit.Runners.UI.RunnerActivity {
// tests can be inside the main assembly
AddTestAssembly(Assembly.GetExecutingAssembly());
AddExecutionAssembly(typeof(ExtensibilityPointFactory).Assembly);
// or in any reference assemblies
//AddTestAssembly(typeof(PortableTests).Assembly);
// or in any assembly that you load (since JIT is available)
#if false
// you can use the default or set your own custom writer (e.g. save to web site and tweet it ;-)
Writer = new TcpTextWriter ("10.0.1.2", 16384);
// start running the test suites as soon as the application is loaded
AutoStart = true;
// crash the application (to ensure it's ended) and return to springboard
TerminateAfterExecution = true;
#endif
// you cannot add more assemblies once calling base
base.OnCreate(bundle);
}

How to compile Xamarin Forms from source and use the assemblies?

I downloaded a copy of the current Xamarin Forms master branch, compiled it, and then I added these compiled assemblies as references to a test project:
Xamarin.Forms.Core
Xamarin.Forms.Platform
Xamarin.Forms.Platform.Android
Xamarin.Forms.Xaml
The test project was created using the Visual Studio Xamarin Forms project template, the only thing I modified is the references in the Core.csproj and Android.csproj to point to the compiled assemblies.
I used the first 3 from the bin\debug\ folder of the Xamarin.Forms.Platform.Android project, and the last one from the Xamarin.Forms.Xaml bin\debug folder.
I run the test project, and it runs fine, I can see the label from the default generated code "Welcome to Xamarin Forms!"
Next, I just modified the MainPage like this:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new ContentPage());
}
}
When I run the app, it gives me an error
System.ArgumentException: element is not of type Xamarin.Forms.View
Parameter name: element
thrown on this line:
void IVisualElementRenderer.SetElement(VisualElement element)
{
if (!(element is TElement))
throw new ArgumentException("element is not of type " + typeof(TElement), nameof(element));
SetElement((TElement)element);
}
which is strange.
The type of the element is Xamarin.Forms.NavigationPage and the stack trace is
Can someone help me running the test project with the compiled assemblies?
UPDATE #1:
The 2nd entry in the call stack shows that it's not able to get the registered renderer(NavigationPageRenderer) for the NavigationPage element and instead it's creating a default renderer(DefaultRenderer), which can't handle the type of element(NavigationPage) so it's throwing the exception I see.
So it appears that for NavigationPage, it doesn't find its renderer(NavigationPageRenderer) in the Registrar.
public static IVisualElementRenderer CreateRenderer(VisualElement element)
{
UpdateGlobalContext(element);
IVisualElementRenderer renderer = Registrar.Registered.GetHandler<IVisualElementRenderer>(element.GetType()) ?? new DefaultRenderer();
renderer.SetElement(element);
return renderer;
}
My feeling is there's a build step I'm not aware about when building Xamarin Forms.
Its crashing as you are calling InitializeComponent on something which doesn't derive from a Forms.Page (i.e. ContentPage etc).
The application itself is not a Page, if you had a page, lets call it 'MyCustomPage' which has some Xaml behind the class would look something like this:
public partial class MyCustomPage : ContentPage
{
public MyCustomPage()
{
InitializeComponent ();
// Some other setup...
}
}
Then in your App constructor you would call
MainPage = new MyCustomPage();
Since you are creating a blank content page from the root of your app, you do not need to call InitializeComponent.
Hope this helps.
You also need to reference
Xamarin.Forms.Platform.Android (Forwarders)
from your Android project.

Resources