Everyday, almost, I use three different shells, Command Prompt, PowerShell, and Bash for Git. I think the interface of those shells has lots to improve. As I am spoiled by good editors like Visual Studio, TextMate, Sublime, Notepad+, (but no Vim yet), I expected the similar level of maturity and convenience.
Console+ is on github now. Please bear in mind, it is code in progress.
So, I wanted to build an interface to them. I'm not building any shell. I'm going to build just an interface. And in this journey, I start learning a few tips with WPF. A geeky joy, as Kent Beck confesses in his book, "TDD By Example".
As this is a WPF application with Win API calls, I don't have enough knowledge or experience. I am more focust on Web development (thought I don't like being labelled as mere web developer as some windows devs believe wrongly web development is child's play)
So, I google a lot to understand how it can possibly work. This is the list of my resources.
I thought I would simply put Icon="/Resource/Icon.ico", but it wasn't. You have to open the property dialog and set it there.
If "AcceptsReturn" and "AcceptsTab" are on, you can't capture those key codes in the event. They are handled within the control, and the event is not escalated. So, turn them off.
Colour is an attribute of the console, and you don't get it from StandardOutput. You have to do something with windows api, and I'm not ready get my hands dirty with win api yet. I'll depriortise this story :-)
Initially, I used System.Timers.Timer to update the screen regularly, but it didn't work. Timer runs in a separate thread, and can't update UI thread. You get "The calling thread cannot access this object ..." error. In this case, DispatcherTimer is handy, as Tick event is fired in the dispatcher thread.
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
_timer.Tick += (o, args) =>
tbxConsole.Text = _console.ReadAll();
_timer.IsEnabled = true;
I need to send user's key input to "cmd.exe" process. In WPF key event, I get KeyEventArgs, but I need to convert it to a character, and it is not possible with the help of win api.
public class KeyHelper
public enum MapType : uint
MAPVK_VK_TO_VSC = 0x0,
MAPVK_VSC_TO_VK = 0x1,
MAPVK_VK_TO_CHAR = 0x2,
MAPVK_VSC_TO_VK_EX = 0x3,
public static extern int ToUnicode(
[Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
public static extern bool GetKeyboardState(byte lpKeyState);
public static extern uint MapVirtualKey(uint uCode, MapType uMapType);
public static char GetCharFromKey(Key key)
char ch = ' ';
int virtualKey = KeyInterop.VirtualKeyFromKey(key);
byte keyboardState = new byte;
uint scanCode = MapVirtualKey((uint)virtualKey, MapType.MAPVK_VK_TO_VSC);
var stringBuilder = new StringBuilder(2);
int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
ch = stringBuilder;
ch = stringBuilder;
Sometimes, not often, I want to return empty character in my method. String has string.empty, but until now, I ddin't know that Char.MinValue exists. It's really handly. Look at this code.
public char GetCharacterFrom(Key key)
if (key == Key.LeftShift)
if (key == Key.Return)
return (char) 13;
With StackOverflow's avalonedit tag, you can read through useful tips
You can download the source code, a sample application, and help file from codeproject.
Changing color of text or highlighting text is quite tricky with Avalon Text Editor. Primarily it's because Avalon is not RichTextEditor but code editor. Text are treated as string and you put meta data on those text if you want to change the format.
You need to create your own DocumentColorizingTransformer to highlight a part of your text, and then add it to your editor's LineTransformers collection. I found an example of custom DocumentColorizingTransformer, bud spend some time to find out how to use it.
public void UpdateConsole()
tbxConsole.Document.Text = _console.ReadAll();
public class ColorizeAvalonEdit : DocumentColorizingTransformer
protected override void ColorizeLine(DocumentLine line)
if (line.Length == 0)
int lineStartOffset = line.Offset;
string text = CurrentContext.Document.GetText(line);
int start = 0;
while ((index = text.IndexOf("Microsoft", start)) >= 0)
lineStartOffset + index, // startOffset
lineStartOffset + index + 10, // endOffset
(VisualLineElement element) =>
// This lambda gets called once for every VisualLineElement
// between the specified offsets.
Typeface tf = element.TextRunProperties.Typeface;
// Replace the typeface with a modified version of
// the same typeface
start = index + 1; // search for next occurrence
to be continued...