Integrating third party controller with MVVMCross

2019-09-02 09:45发布

问题:

I want to use a third party view controller that already inherits from UIViewController (https://bitbucket.org/thedillonb/monotouch.slideoutnavigation/src/f4e51488598b/MonoTouch.SlideoutNavigation?at=master), how would I integrate that with MVVMCross?

I could just take the source and change it to inherit from MvxViewController, but guessing I will run into this with other libraries.

Do I need to implement all the interfaces MvxViewController does? IMvxTouchView? IMvxEventSourceViewController?

回答1:

For this particular case, where you don't actually want to do any data-binding so you can just use a custom presenter - e.g. see @Blounty's answer, or see this project demo - https://github.com/fcaico/MvxSlidingPanels.Touch


If you ever do need to convert third party ViewController base classes so that they support data-binding, then the easiest way is exactly what you guessed:

  • inherit from them to provide an EventSource-ViewController
  • inherit from the EventSource-ViewController to add the Mvx BindingContext

This technique is exactly how MvvmCross itself extends each of UIViewController, UITableViewController, UITabBarController, etc in order to provide data-binding.

For example, see:

  • extending UIViewController to provide an eventsource - MvxEventSourceViewController.cs
  • extending the event source ViewController to provide a binding context - MvxViewController.cs

Note that because C# doesn't have any Multiple-Inhertiance or any true Mixin support, this adaption of ViewControllers does involve a little cut-and-paste, but we have tried to minimise this through the use of event hooks and extension methods.

If it helps, this iOS technique for a previous MvvmCross version was discussed in Integrating Google Mobile Analytics with MVVMCross (obviously this is out of date now - but the general principles kind of remain the same - we adapt an existing viewcontroller via inheritance)

In Android, a similar process is also followed for Activity base classes - see ActionBarSherlock with latest MVVMCross



回答2:

You can use a custom view presenter like below, This is pretty much straight out of my app using the SlideOutNavigation.

public class Presenter
    : IMvxTouchViewPresenter
{
    private readonly MvxApplicationDelegate applicationDelegate;
    private readonly UIWindow window;
    private SlideoutNavigationController slideNavigationController;
    private IMvxTouchViewCreator viewCreator;

    public Presenter(MvxApplicationDelegate applicationDelegate, UIWindow window)
    {
        this.applicationDelegate = applicationDelegate;
        this.window = window;

        this.slideNavigationController = new SlideoutNavigationController();

        this.slideNavigationController.SlideWidth = 200f;

        this.window.RootViewController = this.slideNavigationController;

    }

    public async void Show(MvxViewModelRequest request)
    {
        var creator = Mvx.Resolve<IMvxTouchViewCreator>();

        if (this.slideNavigationController.MenuView == null)
        {
            // TODO: MAke this not be sucky
            this.slideNavigationController.MenuView = (MenuView)creator.CreateView(new MenuViewModel());
            ((MenuView) this.slideNavigationController.MenuView).MenuItemSelectedAction = this.MenuItemSelected;
        }

        var view = creator.CreateView(request);


        this.slideNavigationController.TopView = (UIViewController)view;


    }

    public void ChangePresentation(MvxPresentationHint hint)
    {
        Console.WriteLine("Change Presentation Requested");
    }

    public bool PresentModalViewController(UIViewController controller, bool animated)
    {
        Console.WriteLine("Present View Controller Requested");
        return true;
    }

    public void NativeModalViewControllerDisappearedOnItsOwn()
    {
        Console.WriteLine("NativeModalViewControllerDisappearedOnItsOwn");
    }

    private void MenuItemSelected(string targetType, string objectId)
    {
        var type = Type.GetType(string.Format("App.Core.ViewModels.{0}ViewModel, AppCore", targetType));
        var parameters = new Dictionary<string, string>();
        parameters.Add("objectId", objectId);
        this.Show(new MvxViewModelRequest { ViewModelType = type, ParameterValues = parameters });
    }
}