Archive for 2010 / July

:   :   :  

Import Namespaces for Razor Views

Posted on 28 July 2010 and tagged with , 0 comments

Previously when developing with the WebForms view engine we could use the Web.config file to import namespaces where we stored our extension methods or models. They would then be available to all our views without having to explicitly declare them in each view.

In Razor this is no longer possible due to how it’s built, which is why we have to manually register them in the Application_Start event.

To do this begin with opening Global.asax and create a new method called RegisterGlobalImports, and call it from the Application_Start method. In the newly created method you add all the namespaces you wish to have in your view by calling AddGlobalImport on CodeGeneratorSettings.

public static void RegisterGlobalImports() {
    CodeGeneratorSettings.AddGlobalImport("MvcApplicationRazor.Core.Extensions");
    CodeGeneratorSettings.AddGlobalImport("MvcApplicationRazor.Core.Models");
}

protected void Application_Start() {
    RegisterGlobalImports();
    
    AreaRegistration.RegisterAllAreas();            
    RegisterRoutes(RouteTable.Routes);
}

I usually register extension methods, that should be available in the view, and models so I won’t have to type namespaces over and over again.

Read More »

Getting HTML Colorization with Razor View Engine

Posted on 27 July 2010 and tagged with , , 0 comments

imageToday the Gu announced the first preview of ASP.NET MVC 3, which included the new Razor view engine. I’ve been really excited about it as I feel it makes our views a lot prettier than before with Web Forms view engine. It will also be a lot quicker and smoother to type without all those messy <%-characters.

To the point! I am currently upgrading an existing site to use MVC 3 and Razor. However in this first preview of MVC 3 we won’t have any File Colorization or IntelliSense in .cshtml files. This means it will look like we’re editing in Notepad. It got me wondering if there was a way to at least get some colorization, more specifically HTML colorization. I wandered around in the options of VS2010, and eventually found the place where I could map an extension to a different colorization.

This is how you get HTML colorization in .cshtml files:

  1. Open Tools menu.
  2. Choose Options…
  3. Go to Text Editor, and third choice; File Extension.
  4. Enter cshtml as Extension and choose HTML Editor in the dropdown.
  5. Click Add and OK. Now try to open a .cshtml file – you should get HTML colorization.

Remember to remove this setting when VS2010 officially gets Razor colorization and IntelliSense.

That’s it. Hopefully it will be a little bit easier on your eyes.

Read More »

How to Use the Omnibox API in Google Chrome

Posted on 26 July 2010 and tagged with 0 comments

The Omnibox API in Chrome is currently an experimental API, which means you can’t upload the extension to the gallery if your using it. Though, it works very well for local testing, and that is what we are going to do now.

When I first heard there was going to be an Omnibox API I figured it would let us hook in on every change in the address bar and then add my own results to it. However, this isn’t how the API was implemented, and after reading Aaron’s comment about why, I understand and believe it’s the right way to go.

[…] The omnibox has a very small results space. I'm hesitant to get into a
situation where a bunch of extensions are fighting to make their results the most relevant. […]

Aaron Boodman

In fact the only difference from how I thought it would work is that each extension sets a keyword (like search engines) in the manifest (omnibox_keyword) and this is the word the extension will respond to in the Omnibox. This means that, like Aaron said, we won’t have to fight with other extensions about space – we have our own reserved space in the results list. Smart!

How to Use

Like mentioned earlier, you need to first add a setting to the manifest.json file where you specify the keyword the Omnibox will respond to. This will look identical to how the custom search engines behave in the Omnibox

omnibox-1

Currently the Omnibox API consists of four events:

  • chrome.experimental.omnibox.onInputStarted
  • chrome.experimental.omnibox.onInputChanged
  • chrome.experimental.omnibox.onInputEntered
  • chrome.experimental.omnibox.onInputCancelled

The two events you will use the most are onInputChanged and onInputEntered. InputChanged occurs every time you type something in the Omnibar (after typing the keyword). This is also the event where you will be inserting the suggestions you want to show up in the results list. This is done in the following manner (placed in the background.html file):

chrome.experimental.omnibox.onInputChanged.addListener(function (text, suggest) {
    if (text.search('coffee') > -1) {
        var suggestions = [];

        suggestions.push({ content: 'Coffee - Wikipedia', description: 'Coffee - Wikipedia' });
        suggestions.push({ content: 'Starbucks Coffee', description: 'Starbucks Coffee' });

        suggest(suggestions);
    }
});

The suggest function we are calling at the end wants an array of suggestions. Each suggestion object has tree properties; content, description, and descriptionStyles (optional). The content property is the value the address bar will get when we choose this suggestion, and also the value we receive in the onInputEntered event. The description is the text we see in the results list. Lastly the descriptionStyles; it lets us style the description in different ways, e.g. green, grayed and bold. More on how this works later.

When running this code and typing our keyword in the Omnibox (e.g. “sp”), pressing space, and typing “coffee” you will get the following results:

omnibox-3

Pretty awesome, right! Now this example is quite useless but we could do something much smarter such as submitting this command to a web server, which then starts the coffeemaker and a notification popup is shown when it’s ready.

Whenever you press enter the value will be sent to the event listeners of the onInputEntered event. This event receives the entered text through it’s first parameter “text”. See example:

chrome.experimental.omnibox.onInputEntered.addListener(function (text) {
    alert('You entered: ' + text);
});

If you liked the idea about the coffeemaker, then here is where you will send the command to the web server. Or whatever you like it to do!

Beautify it

The suggestions objects we created earlier only used the content and description properties, and leaving out the descriptionStyles property. This property is quite cool (and nicely implemented). It determines how the description will look in the results list. We can choose between four different styles:

  • styleDim – slightly grayed out, used for helper text
  • styleMatch – used to display matched text, in bold
  • styleUrl – used for URLs and filenames
  • styleNone – resets the style to normal

They are then used by inserting in an array and specifying at which offset it should take effect. This means we can stack up as many different styles we want. We only have to set the offset at which their styles begin. Lets say we have a suggestion where we will display an URL and its page title. It would look like this in code:

var url = 'http://google.com';
var title = 'Google Search';

var suggestion = {
    content: url,
    description: url + ' - ' + title,

    descriptionStyles: [
        chrome.experimental.omnibox.styleUrl(0),
        chrome.experimental.omnibox.styleDim(url.length)
    ]
};

And this is how it looks in our Omnibar:

omnibox-4

Go create some code!

That’s all I have about the Omnibox API. It’s your turn now to create some nice extensions making use of this API, I sure will. However as noted before, you can’t upload extensions using experimental APIs to the extensions gallery. Hopefully it won’t take that long before the Chrome devs finish it.

If anything’s unclear, feel free to leave a comment :-)

Resources

Read More »

Faking Dynamic Properties with PageTypeBuilder in EPiServer

Posted on 21 July 2010 and tagged with , , 0 comments

When building websites in EPiServer you sometimes want a value of a property to be inherited from the parent page. Previously we used Dynamic Properties to have properties inherited, but when using PageTypeBuilder we are spolied with being able to code all our page type properties programactially in classes. However PageTypeBuilder doesn’t support creating Dynamic Properties, but that doesn’t stop us from creating the same functionality with ordinary properties.

After reading Joel’s blog post about dynamic properties with PageTypeBuilder and trying out the snippets of code he wrote, I decided to convert it into an extension method to make it easier to implement in more properties and projects.

Extension Method
public static TProperty GetFakeDynamicProperty<TPageData, TProperty>(this TPageData pageData, Expression<Func<TPageData, TProperty>> expression) where TPageData : PageData where TProperty : class
{
    if (pageData == null) return null;
    if (expression == null) throw new ArgumentException("Missing expression parameter", "expression");

    TProperty value = pageData.GetPropertyValue(expression);

    if (value == null && pageData.ParentLink != null && pageData.PageLink != PageReference.StartPage) {
        var page = DataFactory.Instance.GetPage(pageData.ParentLink) as TPageData;
        value = page != null ? expression.Compile()(page) : null;
    }

    return value;
}
Sample Usage
[PageTypeProperty(Type = typeof(PropertyString), Tab = typeof(Information))]
public string MyInheirtedProperty
{
    get { return this.GetFakeDynamicProperty(page => page.MyInheirtedProperty); }
}

If you know any improvements that can be made to this method – please do leave a comment.

Read More »

Loading Posts...