ssannandeji / Zenject-2019

Dependency Injection Framework for Unity3D
MIT License
2.53k stars 363 forks source link

Editor-time Injection #106

Open hinshun opened 8 years ago

hinshun commented 8 years ago

Perhaps this isn't a use-case for Zenject, but I found myself needing a dependency that needs to be resolved at Editor-time for OnDrawGizmos event callbacks (Drawing helpers for editing a specific type of object)

For now I made a ScriptableObject and added a [SerializeField] reference on the MonoBehaviour, but it really isn't Zenject-style to do this sort of thing. I was wondering if you have encountered this issue before and how you went about solving this?

janus007 commented 8 years ago

I have experienced the same, haven't solved it.

[Serializable]
        public class MetricsMonitorSettings
        {
            [SerializeField]
            public BoolReactiveProperty StreamBrokerMetrics = new BoolReactiveProperty(true);
            [SerializeField]
            public BoolReactiveProperty CubeMetrics = new BoolReactiveProperty(true);

            [Inject]
            StreamBroker _streamBroker;

            public MetricsMonitorSettings()
            {
                CubeMetrics.Subscribe(c => Debug.Log(_streamBroker.Alive));
            }
        }
svermeulen commented 7 years ago

I'm not sure what (if anything) should be done to address this case.

You can install editor-time bindings using StaticContext like this:

[InitializeOnLoad]
public class EditorTimeInstaller
{
    static EditorTimeInstaller()
    {
        var container = StaticContext.Container;
        container.BindInstance("joasdf");
        // etc.
    }
}

But I'm not sure how you'd go about injecting into MonoBehaviours like in your example where you need a dependency in an OnDrawGizmos method, since it's not clear which [Inject] fields would need to be injected at runtime vs editor time.

realworld666 commented 6 years ago

Sorry to necro this thread but I'm looking at something similar. The way I'm approaching it is like this. I have my editor installer class

public class EditorInstaller : MonoBehaviour {

    [InitializeOnLoad]
    public class EditorTimeInstaller: EditorStaticInstaller<EditorTimeInstaller>
    {
        static EditorTimeInstaller()
        {
            Install();
        }

        public override void InstallBindings()
        {
            Debug.Log("Installing editor bindings");
            Container.Bind<ILocalisationManager>().To<LocalisationManager>().FromComponentInHierarchy().AsSingle();
        }
    }
}

and my Editor class has the following

[CustomEditor( typeof( UILocalisation ) )]
public class UILocalisationEditor : Editor
{
    private static string m_FilterString;
    [Inject] private ILocalisationManager _localisation;

    public ILocalisationManager Localisation
    {
        get
        {
            if ( _localisation == null )
            {
                var container = StaticContext.Container;
                _localisation = container.Resolve<ILocalisationManager>();
            }
            return _localisation;
        }
    }

This is throwing an error when I call Resolve

ZenjectException: Found multiple matches when only one was expected for type 'ILocalisationManager'. Object graph:

Zenject.DiContainer.TryGetUniqueProvider (Zenject.InjectContext context) (at Assets/Plugins/Zenject/Source/Main/DiContainer.cs:578) Zenject.DiContainer.Resolve (Zenject.InjectContext context) (at Assets/Plugins/Zenject/Source/Main/DiContainer.cs:939) Zenject.DiContainer.ResolveId (System.Type contractType, System.Object identifier) (at Assets/Plugins/Zenject/Source/Main/DiContainer.cs:2255) Zenject.DiContainer.Resolve (System.Type contractType) (at Assets/Plugins/Zenject/Source/Main/DiContainer.cs:2242) Zenject.DiContainer.Resolve[TContract] () (at Assets/Plugins/Zenject/Source/Main/DiContainer.cs:2237) UILocalisationEditor.get_Localisation () (at Assets/ThriveCore/Editor/Localisation/UILocalisationEditor.cs:23) UILocalisationEditor.OnInspectorGUI () (at Assets/ThriveCore/Editor/Localisation/UILocalisationEditor.cs:45) UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor[] editors, System.Int32 editorIndex, System.Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1253) UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

svermeulen commented 6 years ago

@realworld666

Couple things I notice there

I don't know why you'd be getting that error though

realworld666 commented 6 years ago

I've tried using this too but get the same error Container.Bind<ILocalisationManager>().To<LocalisationManager>().FromNewScriptableObjectResource("Assets/ThriveCore/Resources/LocalisationManager").AsSingle();

svermeulen commented 6 years ago

Installing editor bindings is only printed out once?

realworld666 commented 6 years ago

Yeah it's most strange

svermeulen commented 6 years ago

Maybe add an assert to confirm that Container.HasBinding<ILocalisationManager>() is false in the InstallBinding?

realworld666 commented 6 years ago

Tried that and the assert is not hit

svermeulen commented 6 years ago

If you can provide a small complete example I can look further, otherwise I'm out of guesses

realworld666 commented 6 years ago

I found the bug. I had another class that was doing an editor time injection I wasn't aware of

ATHellboy commented 4 years ago

Hey @realworld666 and @svermeulen Could you tell me how did you bind MonoBehaviour class and inject it in Editor time ? I have an object in the hierarchy and I need it in my custom editor for another object.