What is a pipeline assembly in XNA 4? - visual-studio-2010

I'm trying to build the demo of TiledLib by Nick Gravelyn. I downloaded the ZIP from BitBucket and opened it in Visual Studio 2010. When I try to build, I get the following error:
Essentially, this error for each of three projects:
Error 1 Error loading pipeline assembly "C:\Users\Moshe\Downloads\TiledLib_GS4\TiledLib GS4\References\ContentPipeline\TiledPipelineExtensions.dll". Demo [Windows]
I am new to .NET, so I'm sure that I'm missing some basic concepts. Where might this dependency be referenced, and why won't the assembly load? The file exists at the specified path.
What is a pipeline assembly in XNA 4 and why can't Visual Studio load it?

Update: To your content project, add a reference to: TiledLib_GS4\TiledLib GS4\References\ContentPipeline\TiledPipelineExtensions.dll
Customizing the content pipeline is an advanced game development topic but it is not hard at all (of course depending on what and how you're processing content).
Content Pipeline is the series of steps that are carried out to include content into your game. A wave sound file for example is processed throught the Content Pipeline so that you can use it in your game as a SoundEffect object. The same applies to images that are included in your game as textures (either Texture2D or Texture3D).
When you load content, let's say a 2D Texture, in your XNA game using Content.Load you are invoking a content importer and processor that are already defined within the XNA framework, namely Microsoft.Xna.Framework.Content.Pipeline.Processors.TextureProcessor and Microsoft.Xna.Framework.Content.Pipeline.TextureImporter. There are also similar classes for FBX, Video, Audio content types.
A Pipeline assembly is just that: as assembly that allows you to import content of a certain type. Before we get into more detail note that all of your content is in a special Content Project and this project references assemblies that contain a bunch of out-of-the-box importers that derive from a base Content processor and importer class. These classes allow the Content project type to populate the list of importers that you can use for a certain type, and which you can change using the properties window. Check the screen shots below.
As I gave example of above, there are predefined XNA Content Importers. XNA also allows you to extend the Content Pipeline with your own importing implementations. To do so, XNA provides you with two classes to extend in a Content Pipeline Extension project. The first is a Content Importer and the other is a Content Processor.
A Content Importer is a class that derives from Microsoft.Xna.Framework.Content.Pipeline.ContentImporter and overrides a method called Import that is passed a string filename and an import context object and returns some type of object (generic type T) to use in your game: Texture2D, string or your own sophisticated type. This is called first when you load content.
A Content Processor is a class that provides a method for tranforming content or converting one type of content into another. In XNA it is a subclass of Microsoft.Xna.Framework.Content.Pipeline.ContentProcessor that overrides a method named Process that takes a TInput object and a import context object and returns TOutput. It's called second after the content is imported. This is useful if you import a single type of content in some single way, but you have lots of options as to how to further process it.
To see this in action just add a Content Pipeline Extension project and add to it a Content Processor and Content Importer classes. Do this by adding a new item, there are Item Templates for these two types of classes so you easily a basic no-implementation pipeline. Still, you need your Content Project to reference this Content Pipeline Extension project before you can use it. Once you add this reference, your custom content pipeline appears as a choice in the content processor/importer list that appears in the properties window of an asset. You importer/processor is chosen automatically for assets whose extension matches the one defined in the ContentImporterAttribute decorating your content importer class.
//[using statements omitted for brevity]
// TODO: replace this with the type you want to import.
using TImport = System.String;
namespace ContentPipelineExtension1
{
/// <summary>
/// This class will be instantiated by the XNA Framework Content Pipeline
/// to import a file from disk into the specified type, TImport.
///
/// This should be part of a Content Pipeline Extension Library project.
///
/// TODO: change the ContentImporter attribute to specify the correct file
/// extension, display name, and default processor for this importer.
/// </summary>
[ContentImporter(".abc", DisplayName = "ABC Importer", DefaultProcessor = "AbcProcessor")]
public class ContentImporter1 : ContentImporter<TImport>
{
//Microsoft.Xna.Framework.Content.Pipeline.ContentImporter<T>
public override TImport Import(string filename, ContentImporterContext context)
{
return "This the simplest importer ever that doesn't even take into account the file being imported.";
}
}
}
// TODO: replace these with the processor input and output types.
using TInput = System.String;
using TOutput = System.String;
namespace ContentPipelineExtension1
{
/// <summary>
/// This class will be instantiated by the XNA Framework Content Pipeline
/// to apply custom processing to content data, converting an object of
/// type TInput to TOutput. The input and output types may be the same if
/// the processor wishes to alter data without changing its type.
///
/// This should be part of a Content Pipeline Extension Library project.
///
/// TODO: change the ContentProcessor attribute to specify the correct
/// display name for this processor.
/// </summary>
[ContentProcessor(DisplayName = "ContentPipelineExtension1.ContentProcessor1")]
public class ContentProcessor1 : Microsoft.Xna.Framework.Content.Pipeline.ContentProcessor<TInput, TOutput>
{
public override TOutput Process(TInput input, ContentProcessorContext context)
{
return input + "processed!!!!";
}
}
}
I mention again that your content importer extension must be referenced by your content project. Check the snap shot of my Solution Explorer below.
Also, the content importer is now an option to choose to process your assets. An asset's importer and processor is chosen automatically according to its extension.
This is a great tool if you want other people to collaborate non-programmatically with you in your game. For example you want level designers to create XML files or text files that describe your levels. Now you let them do that and then create content importers that import those files and put them into game objects that you use in your game as if you created them programmatically in the first place.
Now where from does the error you see come from? There is content in your Content Project whose Content Importer and Content Processor properties are set to those that exist in some assembly that is not referenced, but to which the settings of some assets point to as a content importer. The content pipeline extension exists as a DLL in the ZIP you downloaded, see the first statement of the post for the path.
Wow, turns to be quite a post! Have to use it in my blog! :D

Related

What is IViewLocationExpander.PopulateValues() for in Asp.Net Core MVC

I'm using ASP.NET MVC CORE. I have implemented my own ViewLocationExpander so that I can structure my project the way I want and place my views where I like.
This is accomplished by implementing a class that inherits from IViewLocationExpander and most of the work occurs in the following method:
ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
Everything is working pretty sweet but the interface defines a 2nd method that I don't know how to properly implement:
PopulateValues(ViewLocationExpanderContext context)
I've read articles all over the internet about this interface but no one has really provided much info on what exactly this method is for other than saying vague things about how it helps with caching.
I'd really appreciate it if someone could explain how this method is used by the framework and how I can use it appropriately to aid caching if that is indeed what it is for.
Maybe the following additional info taken directly from a GitHub MVC issue can answer your question:
Caching includes the Values dictionary in its lookup. Unless the PopulateValues() method adds distinct information to ViewLocationExpanderContext.Values, the ExpandViewLocations() method will be called just once per original file name i.e. the initial information is cached from then on.
On top of that, the particular example posed by OP can help understand even better, at least that's what happened to me:
His project has views with the same name under two different directory
trees (say Foo and Bar)
Depending on some data extracted by current action context, the view to locate should be under either one of those trees
Without any code in PopulateValues(), view engine will ask once to locate the view, then use view "standard" data (e.g. ControllerName, ActionName, Area, etc.) in order to cache the actual location where view is found.
So, in OP case, once a view location is cached (say e.g. from Foo directory tree) everytime a view with same name is needed it will always be from that tree, there'll be no way to detect if the one in the other Bar tree should have been actually picked up.
The only way for OP is to customize PopulateValues() by adding specific, distinctive view details to Values dictionary: in current scenario, those are the info extracted from current action context.
That additional info are used two-fold: ExpandViewLocations() might use them when invoked in order to determine proper location, while view engine will use them to cache view location once found.
Dec. 2021 update
Official doc page is more descriptive. From Remarks section:
Individual IViewLocationExpanders are invoked in two steps:
(1) PopulateValues(ViewLocationExpanderContext) is invoked and each expander adds values that it would later consume as part of ExpandViewLocations(ViewLocationExpanderContext, IEnumerable<String>). The populated values are used to determine a cache key - if all values are identical to the last time PopulateValues(ViewLocationExpanderContext) was invoked, the cached result is used as the view location.
(2) If no result was found in the cache or if a view was not found at the cached location, ExpandViewLocations(ViewLocationExpanderContext, IEnumerable<String>) is invoked to determine all potential paths for a view.
Haven't messed around with it enough to be able to give you a concrete answer, but have a look at IViewLocationExpander.PopulateValues(ViewLocationExpanderContext context) on the ASP.NET MVC GitHub repo:
public interface IViewLocationExpander
{
/// <summary>
/// Invoked by a <see cref="RazorViewEngine"/> to determine the values that would be consumed by this instance
/// of <see cref="IViewLocationExpander"/>. The calculated values are used to determine if the view location
/// has changed since the last time it was located.
/// </summary>
/// <param name="context">The <see cref="ViewLocationExpanderContext"/> for the current view location
/// expansion operation.</param>
void PopulateValues(ViewLocationExpanderContext context);
// ...other method declarations omitted for brevity
}
Readability format:
"Invoked by a RazorViewEngine to determine the values that would be consumed by this instance of IViewLocationExpander. The calculated values are used to determine if the view location has changed since the last time it was located.
Parameters:
context: The ViewLocationExpanderContext for the current view location expansion operation."
I've had a look at some classes which implement this interface - some declare the method but leave it empty, others implement it.
NonMainPageViewLocationExpander.cs:
public void PopulateValues(ViewLocationExpanderContext context)
{
}
LanguageViewLocationExpander.cs:
private const string ValueKey = "language";
public void PopulateValues(ViewLocationExpanderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// Using CurrentUICulture so it loads the locale specific resources for the views.
#if NET451
context.Values[ValueKey] = Thread.CurrentThread.CurrentUICulture.Name;
#else
context.Values[ValueKey] = CultureInfo.CurrentUICulture.Name;
#endif
}
The article "View Location Expander in ASP.NET Core and MVC 6" provides an example. Here's an excerpt of the explanation:
You can add as many view location expanders as you want. IViewLocationExpander interface has 2 methods, PopulateValues and ExpandViewLocations. PopulateValues method allows you to add values that can be later consumed by ExpandViewLocations method. The values you put in PopulateValues method will be used to find cache key. ExpandViewLocations method will be only invoked if there is no cache result for the cache key or when framework is unable to find the view at the cached result. In the ExpandViewLocations method, you can return your dynamic view locations. Now you can register this view location expander in Startup.cs file,
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
Basically the method can populate values into context.Values that will later be used to determine if a cached list should be used or if the ExpandViewLocations will be called....

Execute different NSDocument subclass according to file extensions

I have written different parsers and different NSDocument subclasses for files with different extensions to visualize the data. I would like to intergrate them together into one application. I am using NSDocument architecture. I am not sure how to map files identified by file extensions to its NSdocument object.
I have tried to add document types in the Xcode info session with class and extensions. However, it seems that it always execute the same parser regardless of the file's extension.
1)Subclass NSDocumentController
a)in your XIB with mainmenu put a new object and give it a class of your new NSDocumentController subclass
or
b)create a new instance before appDidFinishLaunching (initialize, load...)
2)override methods as you see on picture (those which determine type and return document instances) to provide new document instances (as per type)
Read more here
Also scan with your eyes NSDocumentController.h (CMD+SHIFT+O and type NSDoc...)

Properly Refactoring to avoid a Circular Dependency

I am having a problem with a circular dependency. Similar question have been asked and I have read a lot of answers. Most deal with a work-around but I would like to refactor so what I have it correct and I would like some input on where I have gone wrong. I can change what I am doing but not the entire project architecture.
I am using VB.Net in Visual Studio 2012.
I have two class libraries:
DataLayer for accessing the database.
DataObject which contains classes that represents my business objects.
My Presentation Layer calls methods in the DataLayer which returns objects from the DataObject class library.
(I have simplified somewhat – I actually have a controller layer but it needs references to the two class libraries above. This is an existing architecture that is from before my time.)
In the DataObject class library I have an abstract class that represents a file. It has properties such as filename, userID, etc. It also has a method, GetFile(), that I code in the derived classes because there are different ways of getting the file. A DataLayer method returns a collection of these file objects, but I don't want to get the actual file until it's needed.
So far, I have a derived class that calls a webService (using properties from the baseClass) and a derived class that accesses the fileSystem. Both return a byte array representing the file. The calling class does not need to know how the file is retrieved.
Now I have a new requirement to build the file on the fly using data from the database. I can get all the data I need using the properties in the base class.
My issue is that my GetFile() method will need to access my DataLayer class library to pull data from the database which causes a circular dependency. The DataLayer class library has a reference to DataObject since that is what it returns. But now I need to call the DataLayer from a class in DataObjects.
I could call the DataLayer from presentation and pass the result to
my DataObject’s GetFile() method, but then my presentation layer
needs to do something special for this derived class. My goal is
that the derived class handles GetFile without presentation knowing
about the implementation.
I could create a new class library for this DataLayer code but I
don't like a special case.
I could access the DB directly in the DataObject class but that
circumvents the layered architecture.
I can’t change our architecture, but I can change my approach.
Any opinions?
I think I have the answer.
In my concrete class, when I am loading the data initially (in the DataLayer), I will get all the data I need to create the file. I'll store it in a new property in my concrete class which my GetFile() method will use to build the file.
This has a little more overhead - I make DB calls and put all this data in memory when it may not be needed. I'll give it a try and see how performance is.
Any critiques of this approach?

Supporting user-specified file extensions in custom Visual Studio language service

I'm working on a custom Visual Studio language service, and have several questions regarding the way file extensions are bound to a particular language service.
Source files for the language "Example Language" has two primary file extensions: .e1 and .e2. My extension has a class ExampleLanguagePackage which extends Package.
When you use the File → Open command and select a C# file (for example), the "Open" button has a dropdown arrow which allows you to select "Open With...". When you click that button, you are presented with options to open the file in the "CSharp Editor (Default)", "CSharp Editor with Encoding", or any of several other options. How can I provide a similar feature for my language, offering "Example Language (Default)" and "Example Language with Encoding" options?
When you open Tools → Options... → Text Editor → File Extension, you have the ability to bind (for example) the .foo extension to "Microsoft Visual C#" or any of several other options. How can I extend this page to allow user-defined file extensions to be associated with the "Example Language"?
What else should I watch out for when registering these items?
Most of these items are addressed by adding a custom implementation of IVsEditorFactory for your language and using a combination of registration attributes to register it. The actual implementation of this interface is beyond the scope of this question, but the documentation for the interface itself (and linked to that page), along with an example DjangoEditorFactory implementation in the Python Tools for Visual Studio project helped me with my initial implementation.
To support the Example language, I will make the following assumptions.
You've implemented an abstract class ExampleEditorFactory which provides the core implementation of IVsEditorFactory. The class should have a protected constructor with a bool argument to specify whether the factory should prompt the user for an encoding (similar to one of the constructors of the DjangoEditorFactory).
You have a class ExampleEditorFactoryWithoutEncoding which extends ExampleEditorFactory and constructs the base class specifying false for the promptForEncoding argument. This class should be marked with the [Guid] attribute.
You have a class ExampleEditorFactoryWithEncoding which extends ExampleEditorFactory and constructs the base class specifying true for the promptForEncoding argument. This class should be marked with the [Guid] attribute.
You have added the following entries to your VSPackage.resx resources file. The constants can be changed, but be aware that I have used the constant values 101 and 102 below.
101 = Example Language
102 = Example Language with Encoding
Registering the editor factories
The first thing to do is register your editor factories. This is done in two parts.
First, use the ProvideEditorFactoryAttribute. This attribute associates a resource identifier for the display name of the factory with the factory type itself.
[ProvideEditorFactory(typeof(ExampleEditorFactoryWithoutEncoding), 101)]
[ProvideEditorFactory(typeof(ExampleEditorFactoryWithEncoding), 102)]
Next, in the Initialize method of ExampleLanguagePackage, add calls to RegisterEditorFactory after you call base.Initialize().
protected override void Initialize()
{
base.Initialize();
RegisterEditorFactory(new ExampleEditorFactoryWithoutEncoding(this));
RegisterEditorFactory(new ExampleEditorFactoryWithEncoding(this));
}
Associate a logical view with the editor factories
I haven't found all the information I wanted about the use cases for the ProvideEditorLogicalViewAttribute attribute, but it's important to include at least the following. Make sure to register the logical view(s) with both factories you created.
[ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithoutEncoding), VSConstants.LOGVIEWID.TextView_string)]
[ProvideEditorLogicalView(typeof(ExampleEditorFactoryWithEncoding), VSConstants.LOGVIEWID.TextView_string)]
If this step is not done, the feature where double clicking in the output window can take you to a line of code will not work as expected. For example, suppose the output window contained a line like the following.
c:\dev\file.e1(14,3): unexpected expression
Associating the TextView logical view allows the IDE to use your factory when you double click on this output line to take you to line 14, column 3 of the file c:\dev\file.e1. Otherwise it will use a different factory to open a new copy of your document, and the new window will likely be missing many features.
Associate the standard file extensions .e1 and .e2 with the editor factories
This step provides the "Open With..." support for .e1 and .e2 files described in the original question 1. This step is accomplished with the ProvideEditorExtensionAttribute attribute.
The default priority for the primary factory appears to be 50. The factory with explicit encoding should have a priority less than this, and 49 appears to be a good choice. Note that there is no need to specify the NameResourceID named parameter because it was already specified by the ProvideEditorFactoryAttribute usage above (the generated registry keys are identical).
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e1", 50)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".e2", 50)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e1", 49)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".e2", 49)]
Associate the .* extension with the editor factories
This step provides the "Open With..." support for all other files, and adds support for the File Extension options described in the original question 2. This step also uses the ProvideEditorExtensionAttribute attribute, but uses a much lower priority value to ensure the default editors for other file types are not overridden by the setting. Like in the previous step, the factory with explicit encoding is given a lower priority.
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithoutEncoding), ".*", 2)]
[ProvideEditorExtension(typeof(ExampleEditorFactoryWithEncoding), ".*", 1)]
Final notes
This answer does not cover several details.
(High importance for Visual Studio 2012) If you are planning to support Visual Studio 2012, please see the topic Cannot get custom editor to use the provisional tab for details on the new (and otherwise poorly documented) property ProvideEditorFactoryAttribute.CommonPhysicalViewAttributes.
(Unknown importance) The ProvideEditorFactoryAttribute does not support specifying the LinkedEditorGUID value (search down the page). This value would normally be added to the registration of ExampleEditorFactoryWithEncoding, and the value would be the GUID of ExampleEditorFactoryWithoutEncoding.

How to use IProjectionBuffer in MEF without creating editor instance?

I am trying to create a Visual Studio extension which handles a multi-language content type. Much like some mvc-templates and Django or ASP.NET which a certain part of the code is in another language.
I know that I should use Projection and I already checked Django for Visual Studio extension but the solution there includes creating a Language Service and going to the trouble of creating all bits and pieces related to a code editor. Here I am trying to achieve the same goal just by using MEF.
I know that you can use IProjectionBuffer CreateProjectionBuffer() to create a projection but the question is how to replace the current TextBuffer with the created one and when is the best time to do it.
Also one may expect that if he specifies a base definition of type "projection" like this:
[Export]
[Name("Whatever")]
[BaseDefinition("code")]
[BaseDefinition("projection")]
internal static ContentTypeDefinition WhateverContentType = null;
the received TextBuffer in providers to be of type IProjectionBuffer (after all IProjectionBuffer is inherited from ITextBuffer). Which are not and it seems that a projection base definition has no effect what so ever.
So if I want to rephrase my question in a tldr version:
How and when do you apply an IProjectionBuffer to current view (using MEF and without creating an editor instance)?
So if I understand your question correctly, the answer is "you don't." A IWpfTextView is bound to a implementation of ITextBuffer (or a derived type, like IProjectionBuffer) at creation time, and can't be changed. Even if you could, many other extensions and language services would be most surprised by this and would probably crash.
To address your second question about content types: simply declaring you have a base content type of "projection" doesn't make you a projection buffer. All that really states is you might be creating projection buffers of that type, and when you do you want some extra ITagger support so taggers project through to the source buffers as you might expect them to.

Resources