Mvvmcross: Standard way to initialize required internal framework properties beside normal startup & testing; e.g. for WPF design-mode support

Created on 27 Sep 2018  ·  4Comments  ·  Source: MvvmCross/MvvmCross

🏗 Enhancement Proposal

A few months ago I implemented Design-Mode-Support for our application; the views are WPF & the XAML designer supports design mode for views with a special d:DataContext="{d:DesignInstance vm:MenuViewModel, IsDesignTimeCreatable=True}" attribute so the WPF controls in the XAML preview in Visual Studio are already populated with some sample data to make designing & coding easier. I had to create some rudimentary design mode support for the ViewModel (like constructors without arguments; a little design time DI support) but nothing too tricky.
With the recent MvvmCross update this broke because a Trace extension method failed as a side effect to a property change somewhere deep in the framework; the MvxLog.Instance was null.

I looked for places in the source where MvxLog.Instance is already being initialized and this is during normal application startup (MvxSetup) and in some helper for testing (MvxIocSupportingTest).

So I did the same in my InitializeDesignTimeIoCContainer method but I had to use reflection because the MvxLog class is internal as is the static Instance property. Otherwise it's pretty similar to the code found inside MvvmCross.

    [DesignModeOnly]
    static public void InitializeDesignTimeIoCContainer()
    {
        EnforceDesignMode();

        var iocProvider = MvxIoCProvider.Initialize();
        Mvx.IoCProvider.RegisterSingleton(iocProvider);

        // Access internal class MvxLog
        var mvxLogClass = typeof(MvxLogExtensions).Assembly.GetType("MvvmCross.Logging.MvxLog");
        var globalLog = new DesignModeLogProvider().GetLogFor(mvxLogClass);

        // Set static Instance property of MvxLog to globalLog
        PropertyInfo propInfo = mvxLogClass.GetProperty("Instance", BindingFlags.Static | BindingFlags.NonPublic);
        propInfo.SetValue(mvxLogClass, globalLog);

        Mvx.IoCProvider.RegisterSingleton(globalLog);

        Mvx.IoCProvider.RegisterSingleton<IFMModuleService>(() => new FMModuleServiceMock());
    }

Now my design mode support is working again - until the next change...

I understand that this currently isn't a supported scenario so I didn't file this issue as a regression.
Nevertheless here is a real need & my colleagues are enjoying the design time feature so I don't want it to go away.

Some official way to initialize MvxLog.Instance - or better all required internal "properties" - for cases like mine would be very much appreciated.

I'd work on a PR but some guidance would be required.

Pitch

Beside normal application startup there is already a need when it comes to testing to initialize properties in internal classes like MvxLog.Instance. It would be great if a more general solution would be available, e.g. for design time support as explained above. At least there should be a way to initialize the required classes so that no reflection has to be used.

Platforms affected (mark all that apply)

  • [x] :iphone: iOS
  • [x] :robot: Android
  • [x] :checkered_flag: WPF
  • [x] :earth_americas: UWP
  • [x] :apple: MacOS
  • [x] :tv: tvOS
  • [x] :monkey: Xamarin.Forms
feature up-for-grabs

Most helpful comment

I think this is vote number 2 for making MvxLog not internal. Alternatively as you say we should provide a Design Time helper, which helps setting up all the necessary stuff, similar to what we do in our Tests.

@martijn00, @nickrandolph what do you think?

All 4 comments

This sounds kind of what we are doing for our UnitTests: https://github.com/MvvmCross/MvvmCross/blob/develop/MvvmCross.Tests/MvxIoCSupportingTest.cs

GitHub
The .NET MVVM framework for cross-platform solutions, including Xamarin.iOS, Xamarin.Android, Windows and Mac. - MvvmCross/MvvmCross

@Cheesebaron Exactly! (BTW - I mentioned the class in my - pretty long - proposal ;) )

I could imagine some public class that can be used to perform basic initialization - either generally or just for special purposes like design-time support (or testing …).
Some guidance / ideas as how to best integrate this into the large MvvmCross puzzle would be very much appreciated!

A much simpler idea ... One might add lazy initialization to MvxLog.Instance; it might try to get an instance via DI. What do you think of this?

I think this is vote number 2 for making MvxLog not internal. Alternatively as you say we should provide a Design Time helper, which helps setting up all the necessary stuff, similar to what we do in our Tests.

@martijn00, @nickrandolph what do you think?

Any news about this?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Cheesebaron picture Cheesebaron  ·  4Comments

prin53 picture prin53  ·  4Comments

GWawrzeniecki picture GWawrzeniecki  ·  3Comments

neminush picture neminush  ·  4Comments

HaraldMuehlhoffCC picture HaraldMuehlhoffCC  ·  3Comments