Community Feedback Request: ViewLocation Strategy

Topics: Bugs, Extensibility, Feature Requests, Framework Services
Coordinator
Dec 8, 2011 at 1:55 PM

In a recent version we switched View and ViewModel location to a RegEx-based solution rather than the simple string-replace we had before. I've had a lot of issues where people's views aren't resolving because the RegEx rules are fairly strict. I'm thinking of switching the default behavior back to using a string-replace method instead of RegEx and providing the Regex mechanism via a sample so devs can see how to implement that if they want it and still have access to the plumbing code to do it. I'd like to get feedback from the community on whether they think this is a good idea.

Also, if you have any other ideas on how to make ViewLocation more robust, I'd love to hear them.

Dec 9, 2011 at 4:04 AM
Edited Dec 9, 2011 at 4:29 AM

Rob, using RegEx doesn't implicitly make the transformation rules so strict. I designed the built-in rules based on what I thought made sense after getting your input. We can easily make the rules much looser by simply removing some of the built-in transformations. You just have to tell me what you want. As I mentioned at the very beginning, the original name transformation based on bulk string replacement anywhere in the fully-qualified type name just so happened to have worked properly only as a consequence of most people simply not having a need to have entity names that had the word "Model" in them. Consider the simple use case of having an application devoted to fashion models with FashionModel as your entity name. Your view name would be FashionModelView and your view model would be FashionModelViewModel. If the transformer simply stripped out "Model" to resolve the view name, you'd end up with FashionView, which the framework would choke on.

I think the current rules are robust enough to properly extract the base entity name from the view or view model type name in order to avoid the problem associated with the use case mentioned above. However, the namespace transformation might be what's causing people problems. Personally, I thought I designed it to be fairly flexible, but apparently people need even more flexibility.

Right now, the rule is basically like so:

Some.Name.Space.Views.Some.Name.Space.SomeTypeView => Some.Name.Space.ViewModels.Some.Name.Space.SomeTypeViewModel

and vice versa.

IOW, the transformer doesn't care how deeply hierarchical the namespaces are, but it expects "Views" and "ViewModels" to appear at the same hierarchical level. I'm really not sure how you can make this any more flexible.

Dec 9, 2011 at 4:26 AM
Edited Dec 9, 2011 at 4:30 AM

Looking back at some of the questions that I had to answer about the NameTransformer, I think the common denominator was when people didn't have any kind of namespacing convention like the example above. IOW, questions arose when they wanted something like this:

Some.Name.Space.Views.SomeTypeView => Some.Other.Name.Space.ViewModels.SomeTypeViewModel

I think one possible solution would be to create a method that allows people that don't use a namespacing convention to tell the NameTransformer to use an explicit namespace for the views and viewmodels. Then only the type name need be transformed by convention. This method would simply add the appropriate custom rule using the explicit namespaces. That way, none of the existing transformations based on convention need be changed.

Coordinator
Dec 9, 2011 at 12:50 PM

That's a really good idea. That might also help simplify the situation where people have views and view models in different assemblies. How much work do you think that would be? including documenting it in the official docs?

Dec 9, 2011 at 3:25 PM

It shouldn't take too much work to modify the code. The documentation on the other hand... :)

Dec 9, 2011 at 3:41 PM

I also like the idea of the explicit namespace in addition to the existing regex transformer. That way u can add simple conventions without much hassle and for more sophisticated changes, you still got all the power you need (if you know Regex...).

Also, there is still the possibility to override LocateTypeFor... to simply map a view to a specific viewmodel. Maybe we could extend to ViewLocator with a method for mapping views to viewmodels:

ViewLocator.Map<FooView, BarViewModel>();

Dec 9, 2011 at 5:08 PM

OK. I added the changes to my local repository. This code will give you an idea of how it works. Let me know what you think before I check in the changes:

ViewModelLocator.AddNamespaceMapping("Name.Space1.Views", "Name.Space1.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space2.Views", "Name.Space2.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space3.Views", "Name.Space2.ViewModels"); //map to same target namespace

//First mapping
var typename = "Name.Space1.Views.TestView";
var result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space1.ViewModels.TestViewModel, Name.Space1.ViewModels.ITestViewModel, Name.Space1.ViewModels.Test, Name.Space1.ViewModels.ITest

//First mapping with synonym
typename = "Name.Space2.Views.TestPage";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.ITestViewModel

//Second mapping
typename = "Name.Space2.Views.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITest

//Third mapping
typename = "Name.Space3.Views.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITest
//(same as above as expected)

//Built-in mapping still works
typename = "Name.Space.Views.Other.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space.ViewModels.Other.TestViewModel, Name.Space.ViewModels.Other.Test, Name.Space.ViewModels.Other.ITestViewModel, Name.Space.ViewModels.Other.ITest


ViewLocator.AddNamespaceMapping("Name.Space1.ViewModels", "Name.Space1.Views");
//Can map single source namespace to multiple possible target namespaces
ViewLocator.AddNamespaceMapping("Name.Space2.ViewModels", "Name.Space2.Views", "Name.Space3.Views");

//First mapping
typename = "Name.Space1.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space1.Views.TestView

//First mapping with synonym
typename = "Name.Space1.ViewModels.TestPageViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space1.Views.TestPage

//Second mapping
typename = "Name.Space2.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.Views.TestView, Name.Space3.Views.TestView

I'm not sure if there's a use case for mapping a single source to multiple targets, but it seemed appropriate given the ability to map multiple sources to the same target.

Dec 9, 2011 at 5:11 PM
kmees wrote:

I also like the idea of the explicit namespace in addition to the existing regex transformer. That way u can add simple conventions without much hassle and for more sophisticated changes, you still got all the power you need (if you know Regex...).

Also, there is still the possibility to override LocateTypeFor... to simply map a view to a specific viewmodel. Maybe we could extend to ViewLocator with a method for mapping views to viewmodels:

 

ViewLocator.Map<FooView, BarViewModel>();

 


That's kind of an interesting concept. That's getting into the realm of how IoC containers resolve interfaces to concrete types.

Dec 9, 2011 at 5:18 PM

BTW, Rob, if you notice that when resolving ViewModel names, the NameTransformer always returns 4 possible ViewModel names if the View in question ends with "View" but only 2 possible ViewModel names if the View ends with "Page". This was based on a very early discussion with you. Is this correct?

Coordinator
Dec 9, 2011 at 5:28 PM

I believe that is correct, yes. I really like the AddNamespaceMapping method. I think that will solve the majority of the remaining use cases, esp. since we have the remaining RegEx fallback and the mechanism to replace the whole think, if desired. This gives developers several levels of customization based on their needs and experience. So, in short, I approve, and thank you for an excellent contribution. Feel free to push those changes at your earliest convenience. Just as a reminder, if you can, please double check that all platforms build. Their shouldn't be a problem, in this case, I don't think, since it's all basic .NET stuff.

Dec 9, 2011 at 6:17 PM

OK. Built with all platforms. Pushed to Codeplex. I'll post the documentation here later, and then you can merge into the appropriate location.

Dec 9, 2011 at 7:29 PM

Rob, are u interested in the IoC'ish mapping feature? I could hack something over the weekend, see how it feels

Dec 10, 2011 at 1:55 AM

I decided to make some changes to fully build-out the ability add custom synonyms for "View" (e.g. "Form", "Screen", etc.) apart from the built-in support f'or "Page". I added several more methods, including overloads. Here's an update to the sample customization code:

ViewModelLocator.AddNamespaceMapping("Name.Space1.Views", "Name.Space1.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space2.Views", "Name.Space2.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space3.Views", "Name.Space2.ViewModels"); //map to same target namespace
ViewModelLocator.AddNamespaceMapping("Name.Space2.Views", "Name.Space2.Tabs.ViewModels", "Tab"); //Add synonym
ViewModelLocator.AddDefaultTypeMapping("Form"); //Add support for synonym using built-in namespace mapping convention

//First mapping
var typename = "Name.Space1.Views.TestView";
var result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space1.ViewModels.TestViewModel, Name.Space1.ViewModels.Test, Name.Space1.ViewModels.ITestViewModel, Name.Space1.ViewModels.ITest

//Second mapping
typename = "Name.Space2.Views.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.ITest

//Third mapping
typename = "Name.Space3.Views.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.ITest
//(same as above as expected)

//Fourth mapping using sysnonym
typename = "Name.Space2.Views.TestTab";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.Tabs.ViewModels.TestTabViewModel, Name.Space2.Tabs.ViewModels.ITestTabViewModel

//Built-in mapping still works
typename = "Name.Space.Views.Other.TestView";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space.ViewModels.Other.TestViewModel, Name.Space.ViewModels.Other.Test, Name.Space.ViewModels.Other.ITestViewModel, Name.Space.ViewModels.Other.ITest

//Built-in mapping with new synonym
typename = "Name.Space.Views.Other.TestForm";
result = String.Join(", ", ViewModelLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space.ViewModels.Other.TestFormViewModel, Name.Space.ViewModels.Other.ITestFormViewModel


ViewLocator.AddNamespaceMapping("Name.Space1.ViewModels", "Name.Space1.Views");
//Can map single source namespace to multiple possible target namespaces
ViewLocator.AddNamespaceMapping("Name.Space2.ViewModels", new string[] {"Name.Space2.Views", "Name.Space3.Views"} );

//Need to add synonyms last if they're going to be used
ViewLocator.AddNamespaceMapping("Name.Space2.ViewModels", new string[] { "Name.Space2.Views", "Name.Space3.Views" }, "Page");
ViewLocator.AddDefaultTypeMapping("Form"); //Add support for synonym using built-in namespace mapping convention

//First mapping
typename = "Name.Space1.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space1.Views.TestView

//Second mapping
typename = "Name.Space2.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.Views.TestView, Name.Space3.Views.TestView

//Third mapping - same as Second with synonym
typename = "Name.Space2.ViewModels.TestPageViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space2.Views.TestPage, Name.Space3.Views.TestPage

//Fourth mapping - Built-in convention with synonym
typename = "Name.Space.ViewModels.TestFormViewModel";
result = String.Join(", ", ViewLocator.NameTransformer.Transform(typename).ToArray());
//Name.Space.Views.TestForm
Dec 10, 2011 at 2:03 AM

I'm getting a bad gateway error. I'll push the changes later.

Dec 10, 2011 at 5:07 PM
Edited Dec 10, 2011 at 5:21 PM

Just when I thought I was all done... ;)

I made a few important/useful changes. In the last change set, I added support for custom "View type suffixes" or synonyms of "View", but I found that in the ViewLocator there were hardcoded references to the two built-in ones, namely "View" and "Page". These references were in a block of code that strips out the View type suffix and adds ".<Context Name>" to the resolved View name. Obviously, this had to be fixed.

In order to keep track of View type suffixes, I added a private collection of suffixes to ViewLocator. The ViewLocator automatically registers View type suffixes when any of the new "name mapping" methods are called:

AddNamespaceMapping(), AddTypeMapping(), and AddDefaultTypeMapping().

However, we exposed the NameTransformer to allow for adding transformation rules directly. A rule added directly to the NameTransformer may or may not contemplate a concept of a View type suffix, but if it does, the ViewLocator has no way of knowing about it. So I added a method called RegisterViewSuffix(), to allow for cases when rules are added this in "low-level" way. This method is automatically called when adding transformation rules using the new "high-level" name mapping methods listed above.

I also added a public method to both ViewLocator and ViewModelLocator called TransformName(). Although you can still transform names by calling the method on the NameTransformer directly, calling TransformName() from the ViewLocator and ViewModelLocator adds the following capabilities:

  • ViewLocator - allows passing an optional "context" object
  • ViewModelLocator - allows including or excluding interface types

These capabilities correspond to the arguments in ViewLocator.LocateTypeForModelType and ViewModelLocator.LocateTypeForViewType, respectively.

Here's more code to describe how this all works:

ViewModelLocator.AddNamespaceMapping("Name.Space1.Views", "Name.Space1.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space2.Views", "Name.Space2.ViewModels");
ViewModelLocator.AddNamespaceMapping("Name.Space3.Views", "Name.Space2.ViewModels"); //map to same target namespace
ViewModelLocator.AddNamespaceMapping("Name.Space2.Views", "Name.Space2.Tabs.ViewModels", "Tab"); //Add synonym
ViewModelLocator.AddDefaultTypeMapping("Form"); //Add support for synonym using built-in namespace mapping convention

//First mapping
var typename = "Name.Space1.Views.TestView";
var result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space1.ViewModels.TestViewModel, Name.Space1.ViewModels.Test, Name.Space1.ViewModels.ITestViewModel, Name.Space1.ViewModels.ITest

//Second mapping
typename = "Name.Space2.Views.TestView";
result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.ITest

//Second mapping - exclude interfaces
typename = "Name.Space2.Views.TestView";
result = String.Join(", ", ViewModelLocator.TransformName(typename, false).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.Test

//Third mapping
typename = "Name.Space3.Views.TestView";
result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space2.ViewModels.TestViewModel, Name.Space2.ViewModels.Test, Name.Space2.ViewModels.ITestViewModel, Name.Space2.ViewModels.ITest
//(same as above as expected)

//Fourth mapping using sysnonym
typename = "Name.Space2.Views.TestTab";
result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space2.Tabs.ViewModels.TestTabViewModel, Name.Space2.Tabs.ViewModels.ITestTabViewModel

//Built-in mapping still works
typename = "Name.Space.Views.Other.TestView";
result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space.ViewModels.Other.TestViewModel, Name.Space.ViewModels.Other.Test, Name.Space.ViewModels.Other.ITestViewModel, Name.Space.ViewModels.Other.ITest

//Built-in mapping with new synonym
typename = "Name.Space.Views.Other.TestForm";
result = String.Join(", ", ViewModelLocator.TransformName(typename, true).ToArray());
//Name.Space.ViewModels.Other.TestFormViewModel, Name.Space.ViewModels.Other.ITestFormViewModel


ViewLocator.AddNamespaceMapping("Name.Space1.ViewModels", "Name.Space1.Views");
//Can map single source namespace to multiple possible target namespaces
ViewLocator.AddNamespaceMapping("Name.Space2.ViewModels", new string[] { "Name.Space2.Views", "Name.Space3.Views" });

//Need to add synonyms last if they're going to be used
ViewLocator.AddNamespaceMapping("Name.Space2.ViewModels", new string[] { "Name.Space2.Views", "Name.Space3.Views" }, "Page");
ViewLocator.AddDefaultTypeMapping("Form"); //Add support for synonym using built-in namespace mapping convention

//First mapping
typename = "Name.Space1.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Name.Space1.Views.TestView

//Second mapping
typename = "Name.Space2.ViewModels.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Name.Space2.Views.TestView, Name.Space3.Views.TestView

//Third mapping - same as Second with synonym
typename = "Name.Space2.ViewModels.TestPageViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Name.Space2.Views.TestPage, Name.Space3.Views.TestPage

//Fourth mapping - Built-in convention with synonym
typename = "Name.Space.ViewModels.TestFormViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Name.Space.Views.TestForm

//Fourth mapping - use context object (to check if context support works for synonyms)
var context = "Master";
result = String.Join(", ", ViewLocator.TransformName(typename, context).ToArray());
//Name.Space.Views.Test.Master

//Manually add a rule to the NameTransformer to handle synonym
ViewLocator.NameTransformer.AddRule("ScreenViewModel$", "Screen");

typename = "Name.Space.HomeScreenViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Name.Space.HomeScreen

//Test if it works with a context
result = String.Join(", ", ViewLocator.TransformName(typename, context).ToArray());
//Name.Space.HomeScreen (oops!)

//Need to manually register synonym since the rule was added directly to the NameTransformer
ViewLocator.RegisterViewSuffix("Screen");
result = String.Join(", ", ViewLocator.TransformName(typename, context).ToArray());
//Name.Space.Home.Master
Dec 11, 2011 at 8:53 AM

I am probably a bit late, but I feel that using RegEx in this context is a bit of overkill. It is much more easy to customize the ViewLocator directly, instead of definying generic replace rules that would fit everyone needs.

Do not misunderstand me, from a technical point of view it is an amazing implementation (I am a huge fan of RegExp and use them whenever I can), but I think that the purpose is just too 'personal' to be addressed  with a general solution. How many rules are there at the moment? 10? 12? More? And this part keeps getting bigger and bigger to try to solve every possible scenario. View/ViewModel location is of course an hot topic in every MVVM framework, but I fear that this is taking just too much space in the framework.

Moreover, there are certain scenarios where this method of view resolution is in the way: what if I want to implement a skin-based locator, where part of the namespace is the skin name, for example? Should I extend the view-location rules? I fear that the easiest and more intuitive way is replacing current implementation with a custom one.

In few words, somehow I feel that the RegExp implementation is a bit too huge compared to its purpose... but maybe is just my personal feeling.

Coordinator
Dec 11, 2011 at 2:09 PM

Thanks for the feedback BladeWise. I'm taking it into consideration.

Dec 11, 2011 at 3:24 PM

Rob, I'm doing the documentation in a Word document. Is there a way that I can get it to you? I can send you a draft to get your input on whether or not it's detailed enough or too detailed. I suspect it could be more the latter than the former. :)

Dec 11, 2011 at 3:43 PM
Edited Dec 11, 2011 at 4:03 PM
BladeWise wrote:

I am probably a bit late, but I feel that using RegEx in this context is a bit of overkill. It is much more easy to customize the ViewLocator directly, instead of definying generic replace rules that would fit everyone needs.

Do not misunderstand me, from a technical point of view it is an amazing implementation (I am a huge fan of RegExp and use them whenever I can), but I think that the purpose is just too 'personal' to be addressed  with a general solution. How many rules are there at the moment? 10? 12? More? And this part keeps getting bigger and bigger to try to solve every possible scenario. View/ViewModel location is of course an hot topic in every MVVM framework, but I fear that this is taking just too much space in the framework.

Moreover, there are certain scenarios where this method of view resolution is in the way: what if I want to implement a skin-based locator, where part of the namespace is the skin name, for example? Should I extend the view-location rules? I fear that the easiest and more intuitive way is replacing current implementation with a custom one.

In few words, somehow I feel that the RegExp implementation is a bit too huge compared to its purpose... but maybe is just my personal feeling.

In the documentation that I'm working on, I explained what difficulties arise from attempting to customize the name transformations through the NameTransformer and through using regular expressions in general. Part of the complexity of using the NameTransformer has to do with there being two elements of name transformation: that of the the type's name itself and that of the namespace of the type. These tranformations cannot be customized independently of each other through the NameTransformer without an understanding of regular expressions. I suspect that many people don't even bother looking at the source code of the locator classes to use the built-in transformation rules as a template for customization.

Furthermore, I think that the reason that we get "Can't find the view" type posts here (which seem to have decreased anyway with the last build) is because the standard naming conventions supported by the framework haven't been described in enough detail. I attempted to do this in the documentation that I'm working on.

As for the code itself, the changes that I made address the need for there to be a more domain-specific way of customizing the name transformations (i.e. having the locator classes contemplate both type names as well as namespaces whereas the NameTransformer only understands generic name transformation). In addition, methods like the AddNamespaceMapping() used in the sample code above don't require knowledge of regular expressions at all.

At the very least, I think we need to include a sample project (perhaps a simple console application) that pretty much does exactly what the sample code above does.

Coordinator
Dec 12, 2011 at 12:45 PM

If you want, you can create a new ticket for "documenting name transformations" and attach the word document there.

Dec 12, 2011 at 7:10 PM

I'll post the document later. I did have to push one more small change to avoid a potential problem with the AddNamespaceMapping() method. I needed to add some escape characters to the regular expression since the dots in the namespace name are also special characters in regular expression syntax. I also added a couple of small features: "append target to source" mapping as well as support of wildcard "*".

//Test "append to source" mapping
//Null string or String.Empty passed as source namespace is special case
//Note the need to prepend target namespace with "." to make this work
ViewLocator.AddNamespaceMapping("", ".Appended");
typename = "Some.Name.Space.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some.Name.Space.Appended.TestView

//Standard explicit namespace mapping
ViewLocator.AddNamespaceMapping("Some.Name.Space", "Some2.Name2.Space2");
typename = "Some.Name.Space.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some2.Name2.Space2.TestView

//Wildcard at the beginning
ViewLocator.AddNamespaceMapping("*.Some.Name.Space", "Some3.Name3.Space3");
typename = "MyProject.Some.Name.Space.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some3.Name3.Space3.TestView

//Wildcard at beginning and end
ViewLocator.AddNamespaceMapping("*.TestNS.*", "Some4.Name4.Space4");
typename = "Some.TestNS.Other.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some4.Name4.Space4.TestView

typename = "Some.TestNS.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some4.Name4.Space4.TestView

typename = "TestNS.Other.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some4.Name4.Space4.TestView

typename = "TestNS.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//Some4.Name4.Space4.TestView

//Test if non-matching pattern reverts back to original "append to source" mapping
typename = "TestNS1.TestViewModel";
result = String.Join(", ", ViewLocator.TransformName(typename).ToArray());
//TestNS1.Appended.TestView

 

Dec 14, 2011 at 11:45 AM

I uploaded the documentation to the Issue Tracker. I also pushed another update to the source. I needed to added a new class file in this change set. I updated the Silverlight, WPF, and WP71 projects to add the file reference. I see a WP7 csproj file still in the WP71 folder, but I didn't update that one.