MVVMCross 5.3.2 UWP: Where to Get IMvxWindowsFrame for MvxFormsUwpViewPresenter - windows

I'm working out of the Xamarin Forms for MVVMCross 5 Solution Template and updated the packages to the latest version (5.3.2 for MVVMCross). Doing that changes some namespaces around particularly in the UWP project.
It seems that I need to resolve IMvxViewPresenter as MvxFormsUwpViewPresenter which takes a IMvxWindowsFrame as an argument. In the setup file method of Setup.cs there's a XamlControls.Frame rootFrame passed as an argument but I'm not sure if that's suppose to be cast somehow as IMvxWindowsFrame.
Where can you pull the object that implements IMvxWindowsFrame from or is there another way to turn the rootFrame into an IMvxWindowsFrame legitimately.
public class Setup : MvxFormsWindowsSetup
{
private readonly LaunchActivatedEventArgs _launchActivatedEventArgs;
public Setup(XamlControls.Frame rootFrame, LaunchActivatedEventArgs e) : base(rootFrame, e)
{
_launchActivatedEventArgs = e;
// Mvx.RegisterSingleton<IMvxWindowsFrame>(rootFrame);
}
protected override void InitializeFirstChance()
{
base.InitializeFirstChance();
Mvx.RegisterSingleton<Core.Services.ILocalizeService>(new Services.LocalizeService());
Mvx.RegisterSingleton<ISettings>(CrossSettings.Current);
Mvx.RegisterType<IMvxViewPresenter, MvxFormsUwpViewPresenter>();
}
protected override MvxFormsApplication CreateFormsApplication()
{
return new Core.FormsApp();
}
protected override IMvxApplication CreateApp()
{
return new Core.MvxApp();
}
protected override IMvxTrace CreateDebugTrace()
{
return new Core.DebugTrace();
}
}
public sealed partial class MainPage : WindowsPage
{
public MainPage()
{
this.InitializeComponent();
var start = Mvx.Resolve<IMvxAppStart>();
start.Start();
var presenter = Mvx.Resolve<IMvxViewPresenter>() as MvxFormsUwpViewPresenter;
LoadApplication(presenter.FormsApplication);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
}
EDIT: I've been looking more into the class MvxFormsWindowsSetup in the source code at https://github.com/MvvmCross/MvvmCross/blob/develop/MvvmCross-Forms/MvvmCross.Forms.Uwp/Platform/MvxFormsWindowsSetup.cs. It appears that in the method CreateViewPresenter that the IMvxViewPresenter is registered as a singleton with the MvxWrappedFrame already inside but by default the code does not resolve when calling var presenter = Mvx.Resolve() as MvxFormsUwpViewPresenter; in the windows page. Possible bug? Trying to see if I can resolve it myself.
Looks like it fails to resolve even if I put the code right after when Mvx is suppose to register the type / singleton
protected override IMvxWindowsViewPresenter CreateViewPresenter(IMvxWindowsFrame rootFrame)
{
var presenter = new MvxFormsUwpViewPresenter(rootFrame, FormsApplication);
Mvx.RegisterSingleton<IMvxFormsViewPresenter>(presenter);
var presenter2 = Mvx.GetSingleton<IMvxViewPresenter>() as MvxFormsUwpViewPresenter;
return presenter;
}

When updating to MvvmCross 5.3.2 for UWP, the presenter needs to resolve as IMvxFormsViewPresenter rather than IMvxViewPresenter. Change the interface type and it should load properly.
public MainPage()
{
this.InitializeComponent();
var start = Mvx.Resolve<IMvxAppStart>();
start.Start();
var presenter = Mvx.Resolve<IMvxFormsViewPresenter>() as MvxFormsUwpViewPresenter;
LoadApplication(presenter.FormsApplication);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}

Related

Delegate method `WKWebView CreateWebView` method is not getting called

I am using Xamarin (C#) code for a macOS app. I have created the WKWebView and have outlet, added Navigation and UI delegates and trying to open an URL.
The Navigation delegates methods are getting called, but not sure what am I missing that UI Delegates method is not getting called.
Any help / guidance what to look for, or what mistake I am doing here, please.
Here's the code and image of same:
public override void ViewDidLoad()
{
base.ViewDidLoad();
var url = new NSUrl("https://google.com");
var request = new NSMutableUrlRequest(url);
_webView.UIDelegate = new WebViewDelegate();
_webView.NavigationDelegate = new WebViewNavigationDelegate();
_webView.LoadRequest(request);
}
}
internal class WebViewDelegate : WKUIDelegate
{
public override WKWebView CreateWebView(WKWebView webView, WKWebViewConfiguration configuration, WKNavigationAction navigationAction, WKWindowFeatures windowFeatures)
{
Console.WriteLine("this doesn't reach");
return null;
}
}
internal class WebViewNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
Console.WriteLine("this prints");
}
}

Application get stuck at SplashScreen after MvvmCross upgrade to 8.x

I upgraded all MvvmCross libraries from 7.1.2 to 8.0.0. According to "Upgrade from 7 to 8" tutorial from mvvmcross documentation, I have implemented necessary changes (override CreateLogProvider and CreateLogFactory methods and added iocProvider as parameter to InitializeFirstChance, InitializeLastChance, InitializeNavigationService and CreateApp):
public class Setup : MvxAndroidSetup
{
protected override IMvxAndroidViewPresenter CreateViewPresenter() => new HistoryViewPresenter(ViewAssemblies);
protected override void InitializeFirstChance(IMvxIoCProvider iocProvider)
{
base.InitializeFirstChance(iocProvider);
//Things are done here
}
protected override void InitializeLastChance(IMvxIoCProvider iocProvider)
{
base.InitializeLastChance(iocProvider);
//Things are done here
}
protected override IMvxNavigationService InitializeNavigationService(IMvxIoCProvider iocProvider)
{
var loader = CreateViewModelLoader(iocProvider);
Mvx.IoCProvider.RegisterSingleton<IMvxViewModelLoader>(loader);
InitializeViewDispatcher(iocProvider);
var dispatcher = CreateViewDispatcher();
Mvx.IoCProvider.RegisterSingleton(dispatcher);
var navigationService = new DeepNavigationService(null, loader, dispatcher, iocProvider);
Mvx.IoCProvider.RegisterSingleton<IMvxNavigationService>(navigationService);
return navigationService;
}
//Another things are done here
protected override IMvxApplication CreateApp(IMvxIoCProvider iocProvider)
{
return new App();
}
protected override ILoggerProvider CreateLogProvider()
{
return new SerilogLoggerProvider();
}
protected override ILoggerFactory CreateLogFactory()
{
Serilog.Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.CreateLogger();
return new SerilogLoggerFactory();
}
}
I have also created custom app start in Core project and set this class RegisterCustomAppStart:
public class AppStart : MvxAppStart
{
public AppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService) { }
protected override Task NavigateToFirstViewModel(object hint = null)
{
return NavigationService.Navigate<StartupViewModel>();
}
}
public class App : MvxApplication
{
public override void Initialize()
{
//Services and Singletons are registered here.
RegisterCustomAppStart<AppStart>();
}
}
And here is the issue- when I run app, my app get stuck in SplashScreen. Did anyone face similar issue? On the previous version, everything was fine. I would be grateful for some advice how to fix that
I resolved this issue - I changed line:
var dispatcher = CreateViewDispatcher();
For:
var dispatcher = Mvx.IoCProvider.Resolve<IMvxViewDispatcher>();
And it works.

ObservableCollection made of strings Not updating

Ok, so, I'm trying to link an ObservableCollection from my Android project to my Cross-Platform Project::
I've got this so far...this is in my Cross-platform app
ObservableCollection<String> NewRef = DependencyService.Get<ISlateBluetoothItems>().test().testThing;
NewRef.CollectionChanged += TestThing_CollectionChanged;
listView.ItemsSource = NewRef;
private void TestThing_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
listView.ItemsSource = DependencyService.Get<ISlateBluetoothItems>().test().testThing;
Console.WriteLine("working");
}
The line "working" is never printed even if I make changes to the ObservableCollection on the android portion of my app...
Here's the interface I'm using for the DependencyService:
using System.Collections.ObjectModel;
namespace ThoughtCastRewrite.BluetoothX
{
public interface ISlateBluetoothItems
{
BluetoothItems test();
}
}
Here's the class I use to expose the list:
namespace ThoughtCastRewrite.BluetoothX
{
public class BluetoothItems
{
public ObservableCollection<String> testThing;
public BluetoothItems()
{
testThing = new ObservableCollection<String>();
testThing.Add("wtf?");
}
public void AddThis()
{
testThing.Add("ok");
}
}
}
This is in the Android portion of my app, it implements the ISlateBluetoothItems interface
BluetoothItems bluetoothItems = new BluetoothItems();
then I call
bluetoothItems.AddThis();
but "ok" is not added to my list! I don't get the CollectionChanged event firing off! What's the deal guys? What's the deal?
You should assign your ObservableCollection as a source of your listview only once, not after each change. Changes to the collection will be automaticcly propagated to the listview.

Xamarin Android Share Link/Text via social media from custom renderer

I wan't to share a link via social media from custom renderer
public class CustomActions : ICustomActions
{
Context context = Android.App.Application.Context;
public void ShareThisLink()
{
Intent sharingInt = new Intent(Android.Content.Intent.ActionSend);
sharingInt.SetType("text/plain");
string shareBody = "https://www.google.com";
sharingInt.PutExtra(Android.Content.Intent.ExtraSubject, "Subject");
sharingInt.PutExtra(Android.Content.Intent.ExtraText, shareBody);
context.StartActivity(Intent.CreateChooser(sharingInt, "Share via"));
}
}
This error occur
Android.Util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
even when I added the below code I still get same error
sharingInt.AddFlags(ActivityFlags.NewTask);
The problem is that Intent.CreateChooser creates yet another Intent. What you want to do is to set the flag on this new intent:
public void ShareThisLink()
{
Intent sharingInt = new Intent(Android.Content.Intent.ActionSend);
sharingInt.SetType("text/plain");
string shareBody = "https://www.google.com";
sharingInt.PutExtra(Android.Content.Intent.ExtraSubject, "Subject");
sharingInt.PutExtra(Android.Content.Intent.ExtraText, shareBody);
var intent = Intent.CreateChooser(sharingInt, "Share via");
intent.AddFlags(ActivityFlags.NewTask);
context.StartActivity(intent);
}
Alternatively to avoid the need to do this, you could cache the MainActivity instance Xamarin.Forms uses:
public MainActivity
{
public static MainActivity Instance {get;private set;}
protected override void OnCreate(Bundle bundle)
{
Instance = this;
...
}
}
And then use the Instance as the Context in your code instead of the Application.Context

How to detect when MvxListView is bound and has loaded its bindings?

I've Inherted MvxListView to my CustomMvxListView where I dos something with the visualization when a child has been added or removed.
It works great but can be laggy when many items get bound.
Is there a way to detect when Mvx view controls are bound and loaded there first bound data?
Found a good solution myself;
To track Itemsource changes in Android in a ListView you can use a DataSetObserver.
like:
internal class MyObserver : DataSetObserver
{
private readonly object view;
public MvxListViewNonScrollableObserver(ViewToTrack view)
{
tView = view;
DoSomething():
}
public override void OnChanged()
{
base.OnChanged();
DoSomething():
}
}
Add it to a ListView by:
class MyMvxListView : MvxListView
{
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
itemsourceObserver = new MyObserver(this);
Adapter.RegisterDataSetObserver(itemsourceObserver);
}
protected override void OnDetachedFromWindow()
{
if (itemsourceObserver != null)
{
Adapter.UnregisterDataSetObserver(itemsourceObserver);
itemsourceObserver = null;
}
base.OnDetachedFromWindow();
}
public void DoSomething()
{
}
DoSomething() get raised after load and on every itemsource change.

Resources