I am trying to write a custom method for showing native dialog fragment on Android containing the MAUI ContentPage. I am using a partial class with partial method for that:
public partial void ShowCustomDialog(ContentPage contentPage)
{
if (contentPage.ToPlatform(-MauiContext-) is Android.Views.View androidView)
{
var customDialogFragment = new CustomDialogFragment();
if (customDialogFragment != null && Platform.CurrentActivity is Activity currentActivity)
{
customDialogFragment.Container.AddView(androidView);
customDialogFragment.Show(currentActivity.FragmentManager.BeginTransaction(), null);
}
}
}
The problem is, that the IElementToPlatform() method takes MauiContex as an argument, but I have no idea what is that, and how to recieve one?
I found only one example here: https://vladislavantonyuk.azurewebsites.net/articles/Creating-a-bottom-sheet-using-.NET-MAUI
But problem is that when I am trying to get the MauiContext from the Handler of the view (in my example the ContentPage), the Handler of that view is always null.
Do you have any relevant info about the MauiContext and how to implement it right in my solution please?
Related
I'm starting learning MVVM cross, In the android app, I have a splash screen class:
[Activity(MainLauncher = true,
Label = "#string/app_name",
Theme = "#style/Theme.Splash",
NoHistory = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashScreen : MvxSplashScreenActivity
{
public SplashScreen() : base(Resource.Layout.SplashScreen)
{
}
}
and this is the Setup class:
public class Setup : MvxAndroidSetup
{
protected Setup(Context applicationContext) : base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return null;
}
}
the problem is that the debugger doesn't hit the constructor of the Setup Class, instead I get "An unhandled exception" after the constructor of the splash screen
EDIT
I've already defined the App class in the PCL project:
public class App : MvxApplication
{
public override void Initialize()
{
base.Initialize();
}
also defined the AppStart:
public class AppStart : MvxNavigatingObject, IMvxAppStart
{
public async void Start(object hint = null)
{
//hardcoded login for this demo
//var userService = Mvx.Resolve<IUserDataService>();
//await userService.Login("gillcleeren", "123456");
ShowViewModel<MainViewModel>();
}
}
The main reason behind this project is to understand the sequence of code required and executed by MVVM Cross, so I provide the minimum code till it runs successfully without runtime errors.
Update
I have read your code again more thoroughly and I can see the issue now. You defined the constructor of the Setup class as protected, which makes it invisible for activation.
On MvvmCross for Android the magic happens inside MvxAndroidSetupSingleton class (see the source code here) which searches for the Setup type you defined. The FindSetupType method looks for your defined Setup class first and then inside the CreateSetup method Activator.CreateInstance is used to build the Setup instance. The CreateInstance method variant used however searches only for public constructors, which means it doesn't find your protected one. The result is that it cannot build the Setup class and crashes.
Original answer
The reason this happens is that you have no Core libary that would define the MvvmCross App class and would initialize other required setup. I suggest you to start with a simple tutorial or to look into the official sample projects to see what is necessary to make MvvmCross work in a Xamarin.Android app.
I am developing an IOS application with Xamarin using MvvmCross.
I want to use a tab bar to navigate between my Views. I want to have only 1 storyboard per View and want to navigate and call my views from code.
I've overridden the MvxStoryboardViewsContainer Method CreateViewOfTyp() like the following:
protected override IMvxTouchView CreateViewOfType(Type viewType,
MvxViewModelRequest request)
{
var storyboardAttribute = viewType.GetCustomAttribute<FromStoryboardAttribute>();
if (storyboardAttribute == null) {
return base.CreateViewOfType(viewType, request);
}
string storyboardName = storyboardAttribute.StoryboardName ?? viewType.Name;
return
(IMvxTouchView)
UIStoryboard.FromName(storyboardName, NSBundle.MainBundle).InstantiateInitialViewController();
}
Evrytime I try creating my tab bar I call this Method a try to create a View from my model.
The Problem I am encountering here is that UIStoryboard I instantiate is of type UIViewController and not MvxViewController (therefor the app crashes when it tries to cast).
The actual Controller in question however, should be an MvxViewController!
[FromStoryboard("WorklistView")]
public partial class WorklistViewController :
MvxViewController<WorklistViewModel>
{
public WorklistViewController (IntPtr handle) : base (handle)
{
}
}
I'm not sure what i'm missing? Why is the Controller i get a UIViewController and not the MvxViewController it should be?
Thing is I found a lot about what i am trying to do but i can't figure out what i'm doing different.
I found my mistake and it was quite a stupid one.
My designer class had a different namespace then my controller; god knows why...
Well, it's solved now.
I'm currently reading the navigation section from An Introduction to Xamarin.Forms. One should use the GetMainPage() method. But how should that be used?
The default implementation of the app delegate looks like the following:
Applicaton Delegate:
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init ();
LoadApplication (new App ());
return base.FinishedLaunching (app, options);
}
}
App:
public class App : Application
{
public App ()
{
MainPage = GetMainPage ();
}
public static Page GetMainPage()
{
var mainNav = new NavigationPage(new ListExample());
return mainNav;
}
}
I got it managed to use the GetMainPage()method instead of getting
Application windows are expected to have a root view controller at the end of application launch
If I look into the (old?) examples (example1, example2) the app delegate is different and a CreateViewController() method is available. In my case it is not!
What is the correct way of loading the root page on to the stack?
You don't have to use GetMainPage(); that's just a method you create. The way X.Forms works these days is: it exposes a MainPage property in the Xamarin.Forms Application class. You set this to an instance of a Page. How you create that page is up to you. You can either use
this.MainPage = new ContentPage { Content = ... }
or you create one file per page (which IMHO is best for maintainability):
this.MainPage = new MyLoginPage();
or you use helper methods which create your pages:
this.MainPage = this.GetMainPage();
The main page is the first page of your Forms application. You can set the MainPage property to a different value to show another page.
Earlier versions of Forms used different approaches and not all samples have been updated yet. Now all platforms only need a call to the Forms Init() method and a call to LoadApplication() instead of creating a view controller, an activity or a page (WP8).
I want to get a link to image resource in a MVC view that is part of an Orchard module.
Googling a bit resulted in the following approach:
https://stackoverflow.com/a/9256515/3936440
and its using #Html.ResourceUrl() in views to get the resource URL.
I wonder where the ResourceUrl() comes from as its not documented in MSDN and i cannot use it in my projects either.
Did someone used that approach already and can shed some light on whats missing here?
Update:
I figured it out. The following code works in connection with Orchard modules.
First you need to add a resource manifest to the Orchard module like so
public class ResourceManifest : Orchard.UI.Resources.IResourceManifestProvider
{
public void BuildManifests(Orchard.UI.Resources.ResourceManifestBuilder aBuilder)
{
Orchard.UI.Resources.ResourceManifest lManifest = aBuilder.Add();
string lModulePath = "~/Modules/YourModuleName";
lManifest.DefineResource("ProfilePicture", "User1").SetUrl(lModulePath + "/Images/User1.png");
}
}
Then you extend the Html object:
// This class adds so called "extension methods" to class System.Web.Mvc.HtmlHelper
public static class HtmlHelperExtensions
{
// This method retrieves the URL of a resource defined in ResourceManifest.cs via the Orchard resource management system
public static string ResourceUrl(this System.Web.Mvc.HtmlHelper aHtmlHelper, string aResourceType, string aResourceName)
{
// note:
// resolving Orchard.UI.Resources.IResourceManager via work context of orchard because
// - calling System.Web.Mvc.DependencyResolver.Current.GetService() does not work as it always returns null at this point
// - constructor parameter injection is not allowed in static classes
// - setting the resource manager from another class that uses constructor parameter injection does not work as it causes a "circular component dependency "
Orchard.WorkContext lWorkContext = Orchard.Mvc.Html.HtmlHelperExtensions.GetWorkContext(aHtmlHelper);
Orchard.UI.Resources.IResourceManager lResourceManager = (Orchard.UI.Resources.IResourceManager)lWorkContext.Resolve<Orchard.UI.Resources.IResourceManager>();
if (lResourceManager != null)
{
Orchard.UI.Resources.RequireSettings lSettings = new Orchard.UI.Resources.RequireSettings { Type = aResourceType, Name = aResourceName, BasePath = aResourceType };
Orchard.UI.Resources.ResourceDefinition lResource = lResourceManager.FindResource(lSettings);
if (lResource != null)
{
Orchard.UI.Resources.ResourceRequiredContext lContext = new Orchard.UI.Resources.ResourceRequiredContext { Resource = lResource, Settings = lSettings };
string lAppBasePath = System.Web.HttpRuntime.AppDomainAppVirtualPath;
return lContext.GetResourceUrl(lSettings, lAppBasePath);
}
}
return null;
}
}
and then you can write:
<img src="#Html.ResourceUrl("ProfilePicture", "User1")" />
in an Orchard module view to get appropriate image link for User1.
I hope this helps.
ResourceUrl() is a custom HtmlHelper extension.
The code that you need to implement it is included in the answer you have linked.
You simply need to create a static class that contains the method code.
Asp.net article on how to create custom html helpers
PS: Make sure you import your namespace into the view with #using YourNamespace or add it to the System.Web.Mvc.HtmlHelper class.
How can I pass parameter beetwen pages? I've tried to add parameters to page uri but it didn't work because I can't use onNavigatedTo event on user control.
Please help
You must use OnFragmentNavigation.
public void OnFragmentNavigation(FragmentNavigationEventArgs e)
{
DoYourStuff(e.Fragment)
}
e.Fragement contains everything past the # in the URI. In example, using
NavigationCommands.GoToPage.Execute("/Pages/CustomerPage.xaml#CustomerID=12345", this);
e.Fragment will be "CustomerID=12345"
It looks like you are coming from a client browser showing web pages world. With WPF you own the app! you can simply set the value on the new page before or after navigating, pass it in with a constructor or access it from a location accessible from both pages. It sounds like the parameter is an argument to the page so I would pass it in with a constructor in this case:
public class APage : Page
{
private object myVar; // use whatever Type you want
public APage
{
InitializeComponent();
}
public APage(object arg) : this()
{
this.myVar = args;
}
}