Marquee de Sells: Chris's insight outlet for category 'tools' via OData 2.0 Marquee de Sells: Chris's insight outlet for category 'tools' via ATOM 1.0 csells on twitter

You've reached the internet home of Chris Sells, who has a long history as a contributing member of the Windows developer community. He enjoys long walks on the beach and various computer technologies.




What’s New in the Beta Metro/JS Templates for VS11

The Consumer Preview of Windows 8 (aka the Win8 beta) is now available for download, along with the matching Visual Studio 11 beta. You can download them both from the Developer Center for Metro style Apps and at least when I did the downloading this morning, it was smooth and worked well. In case you’re interested, I downloaded the ISO, not the setup, and I am currently writing this blog entry in Windows Live Writer running inside a WMWare Workstation 8.0 virtual machine running on the Windows 7 host OS running inside Boot Camp on my MacBook Pro. As someone said to me this morning: “That’s a lot of VMs!” Maybe so, but the Win8 and VS11 betas are running surprisingly well inside of my Inception-box.

Metro/JS Templates for VS11 in BUILD

If you played around with the Metro/JS templates in VS11 from the BUILD conference in September, you’ll have noticed that the generated apps were compliant with the Windows 8 UX style guidelines, but that two of the templates – Grip and Split – generated large amounts of code. That’s because these are pretty much the biggest apps that Microsoft has ever shipped as templates. They each have multiples pages and they work hard at being simple but feature complete Metro style apps.

However, as well as the BUILD templates implemented the Win8 UX, their code wasn’t the greatest, for the following reasons:

All of these reasons meant that the functionality of the generate Grid and Split apps made for an instructional start to building your own Metro style apps, assuming you were willing to wade through a great deal of code. The new templates in the Win8 beta solve nearly all of these problems.

Get-VS-11-BetaMetro/JS Templates for VS11 Beta

Out of the box, the Metro/JS templates in the VS11 beta (made available today, Feb 29, 2012), get more betterer as they get more complex.Let’s start simple and work our way up.

image

Blank Application

The Blank Application template is almost the smallest Metro/JS app you can build, except that it includes a reference to the Microsoft Windows Library for JavaScript (aka WinJS):

image

And to be clear, this is a brand new feature. Including WinJS as a reference instead of dropping the code into each project means that MS can shipped a single shared implementation instead of every app in the store duplicating the code. If you want to duplicate the code into your project, you can do so, but you’ll also have to update the URL references to the JS and CSS files from your HTML files, like this snippet from the generated default.html:

default.html
  1. <!-- WinJS references -->
  2. <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
  3. <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
  4. <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

In addition to the new syntax with the leading double-slashes, that the number of WinJS files to include is a far smaller number in the Beta. Now it’s just base.js and ui.js, which makes it easy to decide which one(s) you want and in what order to include them, fixing a common problem in the BUILD bits.

One other thing that’s new in the Blank Application template is that there are stubs for implementing tomb-stoning to easily save and restore your app’s session state in the default.js:

default.js
  1. var app = WinJS.Application;
  2.  
  3. app.onactivated = function (eventObject) {
  4.     if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
  5.         if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
  6.             // TODO: This application has been newly launched. Initialize
  7.             // your application here.
  8.         } else {
  9.             // TODO: This application has been reactivated from suspension.
  10.             // Restore application state here.
  11.         }
  12.         WinJS.UI.processAll();
  13.     }
  14. };
  15.  
  16. app.oncheckpoint = function (eventObject) {
  17.     // TODO: This application is about to be suspended. Save any state
  18.     // that needs to persist across suspensions here. You might use the
  19.     // WinJS.Application.sessionState object, which is automatically
  20.     // saved and restored across suspension. If you need to complete an
  21.     // asynchronous operation before your application is suspended, call
  22.     // eventObject.setPromise().
  23. };

The handling of the terminated state in the onactivated event on line 3 and the checkpoint event handler on like 16 are for reactivating and saving your app state respectively.

And finally, the handy TODO comments are something you’ll find sprinkled throughout the templates based on usability feedback conducted to determine what developers really need help with as they add their own functionality to the app.

Fixed Layout Application

Moving up the complexity scale, the Fixed Layout Application template is meant to do just what it says – provide a jumping off point for apps that are logically fixed layout. The crux of this code is the use of the ViewBox control in the default.html:

default.html
  1. <body>
  2.     <div data-win-control="WinJS.UI.ViewBox">
  3.         <div class="fixedlayout">
  4.             <p>Content goes here</p>
  5.         </div>
  6.     </div>
  7. </body>

Line 2 wraps the content of the app in a ViewBox control, which will scale everything inside of it to the size of the content, which is defined in the default.css file with the fixedLayout style:

default.css
  1. .fixedlayout {
  2.     -ms-grid-columns: 1fr;
  3.     -ms-grid-rows: 1fr;
  4.     display: -ms-grid;
  5.     height: 768px;
  6.     width: 1024px;
  7. }

You’ll see in lines 5 and 6 that the height and width of the div contained in the ViewBox is 768x1024, which means that the content can be created using absolute positioning and sizing. The job of the ViewBox is as the app is resized, either the computer’s resolution changes or more likely the app is moved between landscape, portrait, split and full sizes, the ViewBox will scale the content to take up as much room as possible, keeping the aspect ratio constant and scaling the content such that the app itself can think of itself as logically 768x1024 (or whatever the top-level div’s size is). This is very handy for building things like casual games where you want scaling, but generally not flowing – you want to control where the Scrabble tiles are or the tic-tac-toe pieces and it’s much easier to do that with a fixed size.

And now that I’ve described it, I’ll tell you that this template is the only one that’s structurally identical between BUILD and Beta. Still, it is useful.

Navigation Application

The next one up the ladder is the Navigation Application template, which is where we get the Back button and the support for moving HTML fragments into and out of the DOM just like the user was logically navigation page-to-page. In the BUILD bits, this navigation functionality was packaged in the default.js file, but in the Beta, default.js is just the same as the simpler templates. Instead, the navigation functionality is packaged into a new file: navigator.js. The reason this file is separate is to make it clear if you’d like to implement a different navigation policy, e.g. MVC, then this is the file to start with. Further, while this functionality would seem a shoe-in to be included in WinJS, it’s not quite “baked” enough, which means that MS hasn’t yet decided that this is “the way” to do navigation.

Still, it’s “a way” to do navigation in a Metro/JS app and a pretty useful one. Essential the way it works is that there is a singleton PageControlNavigator in the default.html file that holds the pages as they’re swapped in. The default.html is also where navigator.js is included:

default.html
  1. <script src="/js/navigator.js"></script>
  2. ...
  3. <div id="contenthost" data-win-control="Application7.PageControlNavigator" data-win-options="{home: '/html/homePage.html'}"></div>

The navigator.js file defines the PageControlNavigator control, which holds the logical pages as the user clicks around in the application. The home parameter is where to start the navigation. Navigation is to a Page, which is really a mapping between an HTML file and a set of events to handle over the lifetime of that Page:

homePage.js
  1. // This function is called whenever a user navigates to this page. It
  2. // populates the page elements with the app's data.
  3. function ready(element, options) {
  4.     // TODO: Initialize the fragment here.
  5. }
  6.  
  7. WinJS.UI.Pages.define("/html/homePage.html", {
  8.     ready: ready
  9. });

Of course, navigating to the home page is going to be rare compared to navigating between pages. The easiest way to get a new page to add to your app is to right-click on your project in the Solution Explorer and select Add | New Item:

image

The last item three item templates on the list are for shell contract implementations, which are beyond the scope of this blog post, but the first one is a Page Control, which gives us a triad of HTML, JS and CSS that fits exactly into the navigation model provided by the PageControlNavigator control:

page2.html
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="utf-8">
  5.     <title>page2</title>
  6.  
  7.     <!-- WinJS references -->
  8.     <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
  9.     <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
  10.     <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
  11.    
  12.     <link href="page2.css" rel="stylesheet">
  13.     <script src="page2.js"></script>
  14. </head>
  15. <body>
  16.     <div class="page2 fragment">
  17.         <header aria-label="Header content" role="banner">
  18.             <button class="win-backbutton" aria-label="Back" disabled></button>
  19.             <h1 class="titlearea win-type-ellipsis">
  20.                 <span class="pagetitle">Welcome to page2</span>
  21.             </h1>
  22.         </header>
  23.         <section aria-label="Main content" role="main">
  24.             <p>Content goes here.</p>
  25.         </section>
  26.     </div>
  27. </body>
  28. </html>

 

page2.cs
  1. .page2 p {
  2.     margin-left: 120px;
  3. }

 

page2.js
  1. // This function is called whenever a user navigates to this page. It
  2. // populates the page elements with the app's data.
  3. function ready(element, options) {
  4.     // TODO: Initialize the fragment here.
  5. }
  6.  
  7. function updateLayout(element, viewState) {
  8.     // TODO: Respond to changes in viewState.
  9. }
  10.  
  11. WinJS.UI.Pages.define("/page2.html", {
  12.     ready: ready,
  13.     updateLayout: updateLayout
  14. });

Navigating to this new control defined by these files is a simple matter of calling the navigate method:

homePage.html
  1. <a onclick="WinJS.Navigation.navigate('/page2.html')">Page 2</a>

As far as the user is concerned, the anchor tag shows up as a link like any other:

image

Clicking on “Page 2” fires the onclick event, which calls the navigate method, passing in the path to the HTML file and causes the Page control defined in page2.html, page2.js and page2.css to be loaded:

image 

In addition to whatever content on your Page control, notice that the Back button shows up automatically. The Back button manages navigation via clicking, touching and the browser keys; Ctrl+Left Arrow and Ctrl+Right Arrow work as Back and Forward respectively.

Grid and Split Application

At this point, we’ve covered almost all of the core concepts that make up the Grid and Split applications: they bring in WinJS by reference, they use controls and they use navigation via the Page controls. In fact, even though the Grid app has three pages and the Split app has two, they’re really just the navigation template with the pages to implement the Grid and Split app patterns that MS decided were the major app patterns appropriate for Win8. However, the Grid and Split application templates do have two major features that the other templates don’t have: support for multiple view states and a centralized data model.

Multiple view state support means that as the app is moved between portrait, landscape, full and split, the app adjusts itself to look good in all states. The view state management is mostly handled with CSS styles associated with media modes, like in the Split App’s itemsPage.css:

itemsPage.css
  1. ...
  2. @media screen and (-ms-view-state: snapped) {
  3.     .itemspage .itemslist .win-vertical.win-viewport .win-surface {
  4.         margin-bottom: 30px;
  5.     }
  6. ...

In Metro/JS apps, MS has provided a media query predicate called -ms-view-state, which can be one of the four view states and the styles in the media query block will be applied when the app moves to that state. In addition, if you want to handle the view state change in JS, you can do so with updateLayout event in your Page control, like this snippet from itemsPage.js:

itemsPage.js
  1. // This function updates the page layout in response to viewState changes.
  2. updateLayout: function (element, viewState) {
  3.     var listView = element.querySelector(".itemslist").winControl;
  4.     if (viewState === Windows.UI.ViewManagement.ApplicationViewState.snapped) {
  5.         listView.layout = new ui.ListLayout();
  6.     } else {
  7.         listView.layout = new ui.GridLayout();
  8.     }
  9. }

In this case, the updateLayout event is called when the control is initially created and as the app moves through the view states so it can change the layout style for the ListView control showing the contents of the page:

imageimage

Landscape vs. Snapped view state layout for the itemsPage ListView control

The other major feature of the Grid and Split app templates – and this feature is new in the Beta bits – is the centralized data model, which is where the data for all pages comes from. This data model is defined in data.js and it contains the static group and item data as you just saw. The core of the data is exposed from data.js like so:

data.js
  1. WinJS.Namespace.define("data", {
  2.     items: groupedItems,
  3.     groups: groupedItems.groups,
  4.     getItemsFromGroup: getItemsFromGroup
  5. });

These three members of the data object are used throughout the templates, e.g. in the itemsPage.js ready event handler:

itemsPage.js
  1. // This function is called whenever a user navigates to this page. It
  2. // populates the page elements with the app's data.
  3. ready: function (element, options) {
  4.     var listView = element.querySelector(".itemslist").winControl;
  5.     ui.setOptions(listView, {
  6.         itemDataSource: data.groups.dataSource,
  7.         itemTemplate: element.querySelector(".itemtemplate"),
  8.         oniteminvoked: this.itemInvoked.bind(this),
  9.     });
  10.     this.updateLayout(element, Windows.UI.ViewManagement.ApplicationView.value);
  11. },

Notice that the data.groups property is used on line 6 to perform a data binding operation. That data binding is against the dataSource property of the object returned from data.groups, which itself is created by a method on the WinJS.Binding.List object that holds the grouped item data. It’s this binding list, a new feature in WinJS for the Beta, that makes it easy to move from the static data provided by the templates and dynamic data that your app defines.

The binding list is a binding data source, which means that as you add items to it, it notifies any control that happens to be bound to it. This is especially handy when your app starts up with zero data, but you need to initialize the ListViews such that as the data is available (perhaps from an asynchronous network call), it will be shown.

If you open up the data.js, you’ll see the static sample data:

static sample data
  1. // Each of these sample groups must have a unique key to be displayed
  2. // separately.
  3. var sampleGroups = [
  4.     { key: "group1", title: "Group Title: 1", subtitle: "Group Subtitle: 1", backgroundImage: darkGray, description: groupDescription },
  5.     ...
  6. ];
  7.  
  8. // Each of these sample items should have a reference to a particular
  9. // group.
  10. var sampleItems = [
  11.     { group: sampleGroups[0], title: "Item Title: 1", subtitle: "Item Subtitle: 1", description: itemDescription, content: itemContent, backgroundImage: lightGray },
  12.     ...
  13. ];

The group data has a unique key, a title, a subtitle, a background image and a description, which are all fields that the data templates used in the Split and Grid apps depend upon (although you can change them if you like). The item data has a reference to the group to which it belongs, a title, a subtitle, a description, a background image and the content for the item itself.

The code that populates the binding list with the sample data looks like this:

statically bound data
  1. var list = new WinJS.Binding.List();
  2. var groupedItems = list.createGrouped(groupKeySelector, groupDataSelector);
  3.  
  4. // TODO: Replace the data with your real data.
  5. // You can add data from asynchronous sources whenever it becomes available.
  6. sampleItems.forEach(function (item) {
  7.     list.push(item);
  8. });

As the comment makes clear, it’s this code you’re most likely to want to change. Instead of pulling in static data from the sampleItems array, we want to pull the items in asynchronously, perhaps from an RSS feed or two just like my earlier post:

dynamically bound data
  1. var list = new WinJS.Binding.List();
  2. var groupedItems = list.createGrouped(groupKeySelector, groupDataSelector);
  3.  
  4. // RSS feeds
  5. var feeds = [
  6.     { key: "feed1", title: "Scott Hanselman", subtitle: "a blog", backgroundImage: darkGray, description: "a blog", url: "http://feeds.feedburner.com/ScottHanselman" },
  7.  
  8.     { key: "feed2", title: "Raymond Chen", subtitle: "a blog", backgroundImage: lightGray, description: "a blog", url: "http://blogs.msdn.com/b/oldnewthing/rss.aspx" },
  9.  
  10.     { key: "feed3", title: "Chris Sells", subtitle: "a blog", backgroundImage: mediumGray, description: "a blog", url: "http://sellsbrothers.com/posts/?format=rss" },
  11. ];
  12.  
  13. feeds.forEach(function (feed) {
  14.     WinJS.xhr({ url: feed.url }).then(function (request) { processPosts(feed, request); });
  15. });
  16.  
  17. function processPosts(feed, request) {
  18.     // parse the RSS
  19.     var nodes = request.responseXML.selectNodes("//item");
  20.     for (var i = 0, len = nodes.length; i < len; i++) {
  21.         var node = nodes[i];
  22.         var item = {
  23.             group: feed,
  24.             title: node.selectNodes("title")[0].text,
  25.             subtitle: node.selectNodes("pubDate")[0].text,
  26.             description: "a post",
  27.             content: node.selectNodes("description")[0].text,
  28.             backgroundImage: feed.backgroundImage
  29.         };
  30.         list.push(item);
  31.     }
  32. }

In this case, our group data is a set of RSS feeds, being careful to continue to use the same group field names so I don’t have to update the data templates in the rest of the app. When the app loads, I still create a binding list, but instead of filling it directly, I start an async xhr call (the WinJS XMLHttpRequest wrapper) for each feed, creating an item for each RSS post I find upon a successful completion. Because I’ve left the data model alone and because I’m using the binding list, that’s all I have to change and now the entire app has been updated to support that data:

image

The items page with the set of feeds in the Split app template

image

The split page with the posts from the selected feed

Where Are We?

As you can see, the Metro/JS templates in the VS11 beta start simple and add features with navigation, pages with specific app pattern functionality, multiple view state support and a unified data model. The main difference is the Beta versions of this templates is that code has been simplified, beautified and pushed into WinJS as much as possible to make the inside of your app just as pretty and easy to use as the outside.

Translation

This article has been translated into Serbo-Croatian by Jovana Milutinovich. Enjoy.

1 comment




GUI REPL for Roslyn

If you recall from REPL for the Rosyln CTP 10/2011, I’ve been playing around building a little C# REPL app using Roslyn. That version was built as a Console application, but I’ve refactored and rebuilt it as a WPF application:

image

You can download the source code for both the Console and the WPF versions here:

RoslynRepl Sample Download

The benefit of a real GUI app is that output selection makes a lot more sense and that you could imagine real data visualization into data controls instead of just into strings. However, implementing a REPL shell in a GUI environment requires doing things considerably differently than in a Console app. Besides the stupid things I did, like doing a lot of Console.Write, and things that don’t make sense, like #exit or #prompt, there are a few interesting things that I did with this code, including handling partial submissions, rethinking history and rewiring Console.Write (just ‘cuz it’s stupid when I do it doesn’t mean that it shouldn’t work).

Partial Submissions

In this REPL, I decided that Enter means “execute” or “newline” depending on whether the submission is complete enough, according to Roslyn, to execute or not. If it is, I execute it, produce the output and move focus to either the next or a new submission TextBox. If the submission isn’t yet complete, e.g. "void SayHi() {", then I just put in a newline. Further, I do some work to work properly with selections, i.e. if you press Enter when there’s a selection, the selection will be replaced with the Enter key.

So far I like this model a lot, since I don’t have to something like separate “execute” and “newline” into Enter and Alt+Enter or some such.

Rethinking History

In a GUI shell with partial submissions and multi-line editing, the arrows are important editing keys, so can’t be used for access to previous lines in history. Further, a GUI apps makes it very easy to simply scroll to the command that you want via the mouse or Shift+Tab, so there’s not a lot of use for Alt+Arrow keys. Pressing Enter again replaces the old output (or error) with new output (or error):

imageimage

Currently when you re-execute a command from history, the command stays where it is in the history sequence, but it could as easily move to the end. I haven’t yet decided which I like better.

Redirecting Console.Write

Since this is a REPL environment works and acts like a shell, I expect that Console.Write (and it’s cousins like Console.WriteLine) to work. However, to make that work, I need to redirect standard output:

Console.SetOut(new ReplHostTextWriter(host));

The ReplTextWriterClass simply forwards the text onto the host:

class ReplHostTextWriter : TextWriter {
  readonly IReplHost host;

public ReplHostTextWriter(IReplHost host) { this.host = host; } public override void Write(char value) { host.Write(value.ToString()); } public override Encoding Encoding { get { return Encoding.Default; } } }

The hosts implementation of IReplHost.Write simply forwards it onto the currently executing submission (the ReplSubmissionControl represents both a submission’s input and output bundled together). You’ll notice that the TextWriter takes each character one at a time. It would be nice to do some buffering for efficiency, but you’d also like the output to appear as its produced, so I opted out of buffering.

However, one thing I don’t like is the extra newline at the end of most string output. I want the main window to decide how things are output, setting margins and the newline looks like a wacky margin, so the trailing CR/LF had to go. That’s an interesting algorithm to implement, however, since the characters come in one at a time and not line-by-line. I want separating newlines to appear, just not trailing newlines. I implement this policy with the TrimmedStringBuilder class:

// Output a stream of strings with \r\n pairs potentially spread across strings,
// trimming the trailing \r and \r\n to avoid the output containing the extra spacing.
class TrimmedStringBuilder {
  readonly StringBuilder sb;

  public TrimmedStringBuilder(string s = "") {
    sb = new StringBuilder(s);
  }

  public void Clear() {
    sb.Clear();
  }

  public void Append(string s) {
    sb.Append(s);
  }

  public override string ToString() {
    int len = sb.Length;

    if (len >= 1 && sb[len - 1] == '\r') {
      len -= 1;
    }
    else if (len >= 2 && sb[len - 2] == '\r' && sb[len - 1] == '\n') {
      len -= 2;
    }

    return sb.ToString(0, len);
  }
}

Usage inside the ReplSubmissionControl.Write method is like so:

public partial class ReplSubmissionControl : UserControl {
...
  TrimmedStringBuilder trimmedOutput = new TrimmedStringBuilder();

  public void Write(string s) {
    if (s == null) { trimmedOutput.Clear(); }
    else { trimmedOutput.Append(s); }

    consoleContainer.Content = GetTextControl(trimmedOutput.ToString());
  }
}

Now, as the input comes in one character at a time, the trailing newlines are removed but separating newlines are kept. Also, you may be interested to know that the GetTextControl function builds a new read-only TextBox control on the fly to host the string content. This is so that the text can be selected, which isn’t possible when you set the content directly.

Right now, there’s no support for Console.Read, since I don’t really know how I want that to happen yet. Pop-up a dialog box? Something else?

Completions, Syntax Highlighting and Auto-indent

I was a few hundred lines into implementing completions using Roslyn with the help of the Roslyn team when I realized two things:

  1. Implementing completions to mimic the VS editor is hard.
  2. Completions aren’t enough – I really want an entire C# editor with completions, syntax highlighting and auto-indentation.

Maybe a future release of Roslyn will fix one or both of these issues, but for now, both are out of scope for my little REPL project.

2 comments




REPL for the Rosyln CTP 10/2011

I don’t know what it is, but I’ve long been fascinated with using the C# syntax as a command line execution environment. It could be that PowerShell doesn’t do it for me (I’ve seriously tried half a dozen times or more). It could be that while LINQPad comes really close, I still don’t have enough control over the parsing to really make it work for my day-to-day command line activities. Or it may be that my friend Tim Ewald has always challenged csells to sell C shells by the sea shore.

Roslyn REPL

Whatever it is, I decided to spend my holiday time futzing with the Roslyn 2011 CTP, which is a set of technologies from Microsoft that gives you an API over your C# and VB.NET code.

Why do I care? Well, there are all kinds of cool code analysis and refactoring tools I could build with it and I know some folks are doing just that. In fact, at the BUILD conference, Anders showed off a “Paste as VB” command built with Roslyn that would translate C# to VB slick as you please.

For me, however, the first thing I wanted was a C# REPL environment (Read-Evaluate-Print-Loop). Of course, Roslyn ships out of the box with a REPL tool that you can get to with the View | Other Windows | C# Interactive Window inside Visual Studio 2010. In that code, you can evaluate code like the following:

> 1+1 2
> void SayHi() { Console.WriteLine("hi"); }
> SayHi();
hi

Just like modern dynamic languages, as you type your C# and press Enter, it’s executed immediately, even allowing you to drop things like semi-colons or even calls to WriteLine to get output (notice the first “1+1” expression). This is a wonderful environment in which to experiment with C# interactively, but just like LINQPad, it was a closed environment; the source was not provided!

The Roslyn team does provide a great number of wonderful samples (check the “Microsoft Codename Roslyn CTP - October 2011” folder in your Documents folder after installation). One in particular, called BadPainting, provides a text box for inputting C# that’s executed to add elements to a painting.

But that wasn’t enough for me; I wanted at least a Console-based command line REPL like the cool Python, JavaScript and Ruby kids have. And so, with the help of the Roslyn team (it pays to have friends in low places), I built one:

RoslynRepl Sample Download

Building it (after installing Visual Studio 2010, Visual Studio 2010 SP1, the Visual Studio 2010 SDK and the Roslyn CTP) and running it lets you do the same things that the VS REPL gives you:

RoslynRepl

In implementing my little RoslynRepl tool, I tried to stay as faithful to the VS REPL as possible, including the help implementation:

replhelp

If you’re familiar with the VS REPL commands, you’ll notice that I’ve trimmed the Console version a little as appropriate, most notably the #prompt command, which only has “inline” mode (there is no “margin” in a Console window). Other than that, I’ve built the Console version of REPL for Roslyn such that it works just exactly like the one documented in the Roslyn Walkthrough: Executing Code in the Interactive Window.

Building a REPL for any language is, at you might imagine, a 4-step process:

  1. Read input from the user
  2. Evaluate the input
  3. Print the results
  4. Loop around to do it again until told otherwise

Read

Step 1 is a simple Console.ReadLine. Further, the wonder and beauty of a Windows Console application is that you get complete Up/Down Arrow history, line editing and even obscure commands like F7, which brings up a list of commands in the history:

replbeauty

The reading part of our REPL is easy and has nothing to do with Roslyn. It’s evaluation where things get interesting.

Eval

Before we can start evaluating commands, we have to initialize the scripting engine and set up a session so that as we build up context over time, e.g. defining variables and functions, that context is available to future lines of script:

using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Compilers.Common;
using Roslyn.Scripting;
using Roslyn.Scripting.CSharp;
...
// Initialize the engine
string[] defaultReferences = new string[] { "System", ... }; string[] defaultNamespaces = new string[] { "System", ... }; CommonScriptEngine engine = new ScriptEngine(defaultReferences, defaultNamespaces);
// HACK: work around a known issue where namespaces aren't visible inside functions
foreach (string nm in defaultNamespaces) {
  engine.Execute("using " + nm + ";", session);
}

Session session = Session.Create();

Here we’re creating a ScriptEngine object from the Roslyn.Scripting.CSharp namespace, although I’m assigning it to the base CommonScriptEngine class which can hold a script engine of any language. As part of construction, I pass in the same set of assembly references and namespaces that a default Console application has out of the box and that the VS REPL uses as well. There’s also a small hack to fix a known issue where namespaces aren’t visible during function definitions, but I expect that will be unnecessary in future drops of Roslyn.

Once I’ve got the engine to do the parsing and executing, I creating a Session object to keep context. Now we’re all set to read a line of input and evaluate it:

ParseOptions interactiveOptions =
new ParseOptions(kind: SourceCodeKind.Interactive,
languageVersion: LanguageVersion.CSharp6);
... while (true) { Console.Write("> "); var input = new StringBuilder(); while (true) { string line = Console.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { continue; } // Handle #commands ... // Handle C# (include #define and other directives) input.AppendLine(line); // Check for complete submission if (Syntax.IsCompleteSubmission(
SyntaxTree.ParseCompilationUnit(
input.ToString(), options: interactiveOptions))) {
break;
}
Console.Write(". "); } Execute(input.ToString()); }

The only thing we’re doing that’s at all fancy here is collecting input over multiple lines. This allows you to enter commands over multiple lines:

replmultiline

The IsCompleteSubmission function is the thing that checks whether the script engine will have enough to figure out what the user meant or whether you need to collect more. We do this with a ParseOptions object optimized for “interactive” mode, as opposed to “script” mode (reading scripts from files) or “regular” mode (reading fully formed source code from files). The “interactive” mode lets us do things like “1+1” or “x” where “x” is some known identifier without requiring a call to Console.WriteLine or even a trailing semi-colon, which seems like the right thing to do in a REPL program.

Once we have a complete command, single or multi-line, we can execute it:

public void Execute(string s) {
  try {
    Submission<object> submission = engine.CompileSubmission<object>(s, session);
    object result = submission.Execute();
    bool hasValue;
    ITypeSymbol resultType = submission.Compilation.GetSubmissionResultType(out hasValue);

    // Print the results
    ...
  }
  catch (CompilationErrorException e) {
    Error(e.Diagnostics.Select(d => d.ToString()).ToArray());
  }
  catch (Exception e) {
    Error(e.ToString());
  }
}

Execution is a matter of creating a “submission,” which is a unit of work done by the engine against the session. There are helper methods that make this easier, but we care about the output details so that we can implement our REPL session.

Print

Printing the output depends on the type of a result we get back:

ObjectFormatter formatter =
new ObjectFormatter(maxLineLength: Console.BufferWidth, memberIndentation: " ");
...
Submission
<object> submission = engine.CompileSubmission<object>(s, session); object result = submission.Execute(); bool hasValue; ITypeSymbol resultType =
submission.Compilation.GetSubmissionResultType(out hasValue); // Print the results if (hasValue) { if (resultType != null && resultType.SpecialType == SpecialType.System_Void) { Console.WriteLine(formatter.VoidDisplayString); } else { Console.WriteLine(formatter.FormatObject(result)); } }

As part of the result output, we’re leaning on an instance of an “object formatter” which can trim things for us to the appropriate length and, if necessary, indent multi-line object output.

In the case that there’s an error, we grab the exception information and turn it red:

void Error(params string[] errors) {
  var oldColor = Console.ForegroundColor;
  Console.ForegroundColor = ConsoleColor.Red;
  WriteLine(errors);
  Console.ForegroundColor = oldColor;
}
public void Write(params object[] objects) {
  foreach (var o in objects) { Console.Write(o.ToString()); }
}

void WriteLine(params object[] objects) {
  Write(objects);
  Write("\r\n");
}

replerror

Loop

And then we do it all over again until the program is stopped with the #exit command (Ctrl+Z, Enter works, too).

Where Are We?

Executing lines of C# code, the hardest part of building a C# REPL, has become incredibly easy with Roslyn. The engine does the parsing, the session keeps the context and the submission gives you extra information about the results. To learn more about scripting in Roslyn, I recommend the following resources:

Now I’m off to add Intellisense support. Wish me luck!

4 comments




Updated the CsvFileTester for Jet 4.0

I was playing around building a tool to let me edit a database table in Excel, so I updated my CvsFileTester project to work in a modern world, including the 32-bit only Jet 4.0 driver you've probably go lying around on your HD.

Enjoy.

8 comments




Add "Search the Internet" Back to the Win7 Start Menu

Windows 7 took away a feature I use all the time, as shown on the right: Search the Internet.

Here's what I did all day, every day in Windows Vista: Ctrl+Esc to bring up the Start menu, then I start typing. If I'm searching on my HD, I immediately get matches and I can choose one with just the arrows and the Enter key. If I'm typing in the name of a program in the Start menu, I get those matches and choose one. If I want "calc" or "notepad" I can just type those and those work.

However, 80% of the time, I want to search the internet, so enter my search term, optionally including attributes like "site:", I press, down-arrow once, highlight "Search the Internet" and press Enter. This brings up my default browser with my search results in my default search engine without me having to move the mouse or open the browser and wait for the home page or even decide where I want the search results to come from until after I've entered my search phrase.

And we took it out of Windows 7. : (

But, Shawn VanNess has shown me how to put it back! : )

Download this zip file, execute the .reg file, press Yes and OK a bunch, kill and restart the explorer.exe process and the next time you do the Ctrl+Esc+type+something dance, you'll see your old friend "Search the Internet" right back on the Start menu where Bill intended it to be. Thanks, Shawn!

11 comments




Shawn has prepared Genghis v0.8

Shawn Wildermuth has prepared a v0.8 release of Genghis that includes a bunch of stuff that the folks that put the v0.6 release together dropped. The v0.8 release has all the good stuff from the v0.5 release and all the new stuff from the v0.6 release in a .NET 2.0 package.

Shawn's really done all the work for Genghis since I came to Microsoft. Thanks, Shawn.

0 comments




Genghis moved to CodePlex

Shawn Wildermuth has moved Genghis to CodePlex because GotDotNet Workspaces is going away. I actually really like CodePlex, but not the state those pesky contractors left the Genghis bits in, so we'll be following up with another release in early July to bring sanity back. Thanks, Shawn!

3 comments




Show Me The Templates!

Show Me The Template is a tool for exploring the templates, be their data, control or items panel, that comes with the controls built into WPF for all 6 themes.

Show Me The Template screenshot

Enjoy.

2 comments




Detailed Time Zone Data

A long time ago (2000), I was fascinated with turning a phone number into a time zone so I could tell what time it would be somewhere before I called and woke anyone up (this happened too often : ).

As part of that work, I quickly realized that info in Windows for time zones wasn't detailed enough, so I began looking elsewhere. I found the Time Zone Map Group, which maintains time zone data for all over the world backward through time. This is an amazing accomplishment, since they have to account for every law change as each tin pot dictator comes to power, e.g. George W.

At the time, they had a custom format for the data (and they probably still do, as far as I know), so I wrote a utility to translate the tz format into XML for easy parsing. I literally haven't touched the tool since, but with the recent time zone law changes in the US, I thought folks might be interested. Enjoy.

4 comments




.NET: Decompressing zip file entries into memory

I knew that the J# libraries in .NET had zip file support, but I couldn't find any samples that showed how to decompress the files into memory. The hard part, of course, is that the J# stream objects aren't the same as the .NET stream objects. If you're a Java programmer looking for a familiar library, that's great, but I'm not, so I had to do a little finagling.

The first thing you need to do is to add a reference to the vjslib assembly, which brings in .NET classes in Java namespaces, e.g. java.io. The one we care most about is java.uti.zip, which includes ZipFile and ZipEntry. We also need java.util for the Enumeration class and java.io for the InputStream class. With these in place, we can enumerate a zip file:

using java.util; // all from vjslib assembly
using java.util.zip;
using java.io;
...
static void Main(string[] args) {
  if( args.Length != 1 ) {
    Console.WriteLine("Usage: dumpzipfileoftextfiles <file>");
    return;
  }

  // we're assuming a zip file full of ASCII text files here
  string filename = args[0];
  ZipFile zip = new ZipFile(filename);

  try {
    // enumerate entries in the zip file
    // NOTE: can't enum via foreach -- Java objects don't support it
    Enumeration entries = zip.entries();
    while( entries.hasMoreElements() ) {
      ZipEntry entry = (ZipEntry)entries.nextElement();

      // read text bytes into an ASCII string
      byte[] bytes = ReadZipBytes(zip, entry);
      string s = ASCIIEncoding.ASCII.GetString(bytes);

      // do something w/ the text
      string entryname = entry.getName();
      Console.WriteLine("{0}:\r\n{1}\r\n", entryname, s);
    }
  }
  finally {
    if( zip != null ) { zip.close(); }
  }
}

Notice the use of the Enumeration object so we can enumerate in the Java style and the use of the ZipFile and ZipEntry types. This is all stuff you could find in readily available online samples (I did). The interesting bit is the ReadZipBytes method:

static byte[] ReadZipBytes(ZipFile zip, ZipEntry entry) {
  // read contents of text stream into bytes
  InputStream instream = zip.getInputStream(entry);
  int size = (int)entry.getSize();
  sbyte[] sbytes = new sbyte[size];

  // read all the bytes into memory
  int offset = 0;
  while( true ) {
    int read = instream.read(sbytes, offset, size - offset);
    if( read == -1 ) { break; }
    offset += read;
  }
  instream.close();

  // this is the magic method for converting signed bytes
  // in unsigned bytes for use with the rest of .NET, e.g.
  // Encoding.GetString(byte[]) or new MemoryStream(byte[])
  return (byte[])(object)sbytes;
}

For those of you familiar with Java, I'm just reading the zip file entry data into an array of signed bytes. However, most .NET APIs like unsigned bytes, e.g. "Encoding.GetString(byte[])" or "new MemoryStream(byte[])", which means you've got to convert a signed array of bytes in .NET to an unsigned array of bytes. Unfortunately, just casting doesn't work (the compiler complains). Even more unfortunately, I could find nothing in the Convert or BitConverter classes to perform this feat of magic and the code I wrote was dog slow, so I asked around internally.

Luckily, James Manning, an MS SDE, had the answer: cast the signed byte array to an object first and then to a unsigned byte array. Thank goodness James knew that, because I didn't find anything on this topic. Hopefully future generations will find this missive.

You can download the sample if you like. Enjoy.

17 comments




Number to String Converter

To capture the work that Doug and I did to make Indigo (WCF) and Avalon (WPF) work together, I tore up our PDC sample application into a set of simpler technology samples. To make it fun for myself, as part of these samples, I built a little library for converting numbers into strings of English words, e.g.

Enjoy.

10 comments




RegistrySettingsProvider2

I updated the SDK RegistrySettingsProvider to implement IApplicationSettings and built a sample to demonstrate how to integrate it (or any .NET 2.0 custom settings provider) with the settings designer-generated code. Enjoy.

Discuss

0 comments




Number To String Converter

To capture the work that Doug and I did to make Indigo (WCF) and Avalon (WPF) work together, I tore up our PDC sample application into a set of simpler technology samples. To make it fun for myself, as part of these samples, I built a little library for converting numbers into strings of English words, e.g. 4 is "four:"

To drive home the point (of which there wasn't any because the sample had nothing whatever to do with number to English phrase conversions), I spent some time polishing the algorithm so that it handled decimal points:

and when that didn't satisfy me, I added large numbers and negative numbers:

Before writing this code, I searched the net and didn't find any algorithms that handled both negative numbers and decimal points, let alone for .NET or in the number of lines of code to which I cut it down (93, including comments). I know it's not useful, but it was fun. If you want the code, you can get it by downloading the .NET 3.0 Cross Technology samples and checking out the WinSDK_Samples\CrossTechnology\WpfDataBindingToWcfResults\service\NumberUtility.cs file. I built the file to be dropped into any .NET 2.0+ project (and even .NET 1.x projects, if you remove the "using System.Collections.Generic" statement at the top of the file -- I don't actually use generics), regardless of whether you're using Avalon or Indigo or not.

Enjoy.

Discuss

0 comments




Calling a Remote Index Server from .NET

I was building some code to access Index Server's results via .NET and I got this:

// Catalog specified in connection string
string query = "select Path from Scope() where FREETEXT('foo')";
using( OleDbConnection conn = new OleDbConnection("Provider=MSIDXS.1;Data Source=MyCatalog") ) {
  conn.Open();
  OleDbDataAdapter cmd = new OleDbDataAdapter(query, conn);
  DataSet ds = new DataSet();
  cmd.Fill(ds, "SearchResults");
  DataTable table = ds.Tables[0];
  ds.Tables.Remove(table);
  return table;
}

This came from a combo of stuff I found on the net and my own experimenting. However, I had to get an MS employee who know IS (thanks Chad Ray!) to figure out how to access IS remotely, which I was finally able to get working thusly:

// Server and catalog specified in query string, not connection string
string query = "select Path from MyServer.MyCatalog..Scope() where FREETEXT('foo')";
using( OleDbConnection conn = new OleDbConnection("Provider=MSIDXS.1") ) {
  conn.Open();
  OleDbDataAdapter cmd = new OleDbDataAdapter(query, conn);
  DataSet ds = new DataSet();
  cmd.Fill(ds, "SearchResults");
  DataTable table = ds.Tables[0];
  ds.Tables.Remove(table);
  return table;
}

Also, if the server or catalog name has anything "weird" in it, e.g. those wacky dashes, you're supposed to wrap it in double quotes. My experimenting showed that wrapping any server or catalog name in double quotes worked just fine, e.g.

string query = "select Path from \"MyServer\".\"MyCatalog\"..Scope() where FREETEXT('foo')";

However, if the server name is "localhost" or "127.0.0.1", IS doesn't like it, which meant that I had to check for those server names and drop the ones that used the loopback adapter (although using the machine name of the local machine worked just fine), e.g.

static bool IsLocalHost(string server) {
  return string.IsNullOrEmpty(server) || (string.Compare(server, "localhost", true) == 0) || (string.Compare(server, "127.0.0.1") == 0);
}

string GetPlainTextQueryString(string text, string columns) {
  // IS doesn't like "localhost"
  if( IsLocalHost(_server) ) {
    return string.Format("select {0} from \"{1}\"..Scope() where FREETEXT('{2}')", columns, _catalog, text);
  }
  else {
    return string.Format("select {0} from \"{1}\".\"{2}\"..Scope() where FREETEXT('{3}')", columns, _server, _catalog, text);
  }
}

I'm only posting this 'cuz I couldn't find it on the net and I want to be able to find it again later. : )

7 comments




New Workspace Link for RegexDesigner

Here.

The nice folks at GotDotNet have decided in their infinite wisdom to move all of the workspaces to a new hierarchy w/o forwarding the URLs and then leaving a message behind indicating that such a thing is temporary to keep users on their toes:

"Operational Troubleshooting in Progress
The Gotdotnet team is aware of the current site operational issues and is working on a solution. Thanks for your patience."

Anyway, due to popular demand, I've updated the GotDotNet workspaces link to the RegexDesigner and other tools. Enjoy.

3 comments




My First MsBuild Task

Here. The one where I built my first custom msbuild task.

0 comments




RegexDesigner Updated

RegexDesigner has been updated to v1.1 with support for replacement patterns, national and special symbol support, Ctrl+Tab hotkey support, updated highlighting support for color blind users, Ctrl+A support and the use of a bullet instead of @ for matched whitespace. Thanks to Victor Serbin for putting this update together from source contributed to the GDN workspace.

6 comments




XSLTO: Mapping XSLT to Objects

Here. When Tim Ewald was still a Microsoft employee, he and the next-gen MSDN content management system team experimented with some fun techniques for XSLT to Object mapping. To illustrate this technique, Kim Wolk has built a little prototype that lets you associate an XPATH statement with a method on an object and that method will be invoked for the nodes that match the XPATH statement. Check it out.

Update: Steve Dunn has ported Kim's sample from .NET 2.0 beta to .NET 1.1. Thanks, Steve!

13 comments




Genghis v0.5 Released

After much delay (man, this Microsoft gig keeps a person busy), I'm happy to announce Genghis v0.5:

  • New HtmlLinkLabel class from Jeff Key that knows how to launch IE and EXEs directly w/o requiring you to handle the event
  • Much prettier images in SimplePad from Chris Burrows
  • Updated MRU code from Michael Weinhardt to match .NET event signature conventions and to fix a problem when using more than one MRU components on a single menu
  • Updated FileSearchEngine code from Mike Marshall to check for whole words at beginning and end of line correctly
  • Updated validation code from Michael Weinhardt with support for validating controls at a container level, e.g. validating controls on a tab instead of on an entire form
  • New gradient progress bar from Mike Marshall
  • Updated FileDocument from Chris Sells to match text of Windows Forms Programming to include more MFC-like features like a pluggable scheme for serialization handling, registration of document extension with the shell, and adding to recent docs, i.e. Start->Documents
  • Updated HandleCollector from Ethan Brown to work with .NET 1.0 and .NET 1.1
  • Performance enhancements from Ethan Brown in the MappedDrives and SystemShares classes
  • New user-resizable panel from Ethan Brown
  • Updated WebCommandLineHelper from Andrew Duncan to fix System.IO.FileLoadException in ieexec.exe
  • Updated AniForm from Mike Marshall to support stacking ala SharpReader and fix a terminal server-related bug
  • Updated cool menu sample from Chris Burrows with additional support for abstracting commands from click even handlers
  • Enjoy.

    1 comment




    My First .NET Tool Gets An Update

    Here.

    Given Aaron's wonderful set of .NET XML tools, I don't know why Tony Malandain found my little xmlValid tool for checking XML well-formedness and schema validness, but he did and then added the ability to take XML input from stdin (he apparently uses it to check compressed SVG files).

    What makes this kind of unusual is that I built this tool almost 2.5 years ago. In fact, it was the first .NET tool I posted on my site. Before that, it was all C++ and COM, although almost none of that has gone up since. It was kind of fun digging into that code again. I spent a bunch of time rearranging it to map more closely to my current .NET coding style not because it added any more functionality but because I couldn't stand not to. This developer thing is just a sickness, isn't it? : )

    1 comment




    ImCli Classes Updated for MSNP8

    Here.

    Plenty of folks have asked for updates to my IM client classes to support the new MSNP8 protocol, but only Robert M. Wagner Jr. made the changes and sent them to me. Thanks, Robert!

    1 comment




    ADO.NET CsvFileTester

    CsvFileTester is a tool inspired by Shawn Wildermuth's ExcelFileTester, which he wrote 'cuz I kept asking him how to do queries on .xls files. However, because the Excel query language has no where or order by clauses, I gave that up in favor of comma-separated text files.

    I wrote CsvFileTester (with Shawn's help) to explore the ADO.NET/ODBC/JET support for CSV files and I was amazed at how comprehensive the support was. And, since I can never remember the syntax and limitations between one use of Jet expression syntax and the next, I put a bunch of samples in the combobox.

    Enjoy.

    0 comments




    .NET FormatDesigner

    FormatDesigner is an application to experiment with the format strings used to format data in String.Format and various type's ToString functions.

    Click here to launch the application directly (requires the .NET Framework 1.1).

    Click here to download the source code.

    Enjoy.

    0 comments




    Genghis Moved to GotDotNet Workspaces 1.0

    Here. Now that GotDotNet Workspaces 1.0 has shipped (congrats!) Mike has moved Genghis there. Feel free to apply for membership if you've already contributed source to Genghis or if there's something you'd like to add.

    0 comments




    XmlSerializerPreCompiler

    Tired of the XmlSerializer's generic "File or assembly name ctewkx4b.dll, or one of its dependencies, was not found" exception? The XmlSerializerPreCompiler tools checks to see if a type can be serialized by the XmlSerializer class and if it can't, shows the compiler errors happening behind the scenes so that the type can be modified. Enjoy.

    This just in: Mathew Nolton has posted a GUI front-end to my XmlSerializerPreCompiler that you might find useful. Thanks, Matt!

    0 comments




    48 older posts       No newer posts

    Powered By ASP.NET

    Hosted by SecureWebs

    Mensa

    IEEE