Search code examples
dynamicproxycaliburn.microcaliburn

Caliburn with Castles DynamicProxy: Cannot find view


For a project im working on I try to combine caliburn with castles dynamicProxy. My aim is to intercept all methods of the view model objects that are invoked by the view. Caliburn attaches the view Model methods automatically by convention (thats the principle used by caliburn to connect e.g. button commands to view model methods) tó specific elements of the view. Therefore I have overriden caliburns GetInstance method which is used to instantiate the ViewModel classes. Within this method I wrap every viewmodel with a dynmiac proxy and then return it:

protected override object GetInstance(Type serviceType, string key)
{
    var instance = container.GetInstance(serviceType, key);

    if (instance != null)
    {
        object ret = pg.CreateClassProxyWithTarget(instance.GetType(), (instance), new LoggingInterceptor());
        return ret;
    }

    throw new Exception("Could not locate any instances.");
    //return null;
}

Unfortunatley after this change my View displays just

Cannot find view for Castle.Proxies.FirstViewModelProxy.

Because I know castles dynamicproxy adds the string "Proxy" to the end of the newly created type and that caliburn replaces the word Model in the end of a string and then tries to find the corresponding view using this string I added another NameTransformer rule:

public CaliburnBootstrapper() 
    {
        LogManager.GetLog = type => new DebugLogger(type);
        Initialize();
        ViewLocator.NameTransformer.AddRule("ModelProxy$", string.Empty);
    }

This however did not change anything. How to solve this problem?


Solution

  • After some more research i found out myself how to do that: Caliburn allows to exchange the method responsible for name transformations of view models to view. So what i did was then calling the original name transform method in my own. When it doesnt returns anything I try my own logic on it. That did the trick.

            Func<string, object, IEnumerable<string>> orig = ViewLocator.TransformName;
            ViewLocator.TransformName = new Func<string,object,IEnumerable<string>>(
                delegate(string a, object b )
                {
                    IEnumerable<string> ret =  orig(a,b);
                    if (ret.Count() > 0)
                    {
                        return ret;
                    }
    
                    a = Regex.Replace(a, "^Castle.Proxies", "CaliburnSample.Views");
                    a = Regex.Replace(a, "ModelProxy$", string.Empty);
                    a = Regex.Replace(a, "Model$", string.Empty);
                    return new string[] { a };
                }
            );
    

    Update: Almost everything works fine. The buttons are bound by convention to the methods and so on. But unfortunatley the notifications of properties are not working anymore. The view is not updated anymore with the new contents of the properties although they are bound by caliburn:

    INFO: [2015-12-09T11:36:30.2646933+01:00] Binding Convention Applied: Element TxtMsg.