Robert Westerlund

A developer's blog on code, technology and tools in the Web, .NET and other development areas.

NAVIGATION - SEARCH

Converting Fixed Column Length Text Files into Objects using PowerShell

UPDATE 2014-03-24: Note that this version is written for PowerShell version 4 and will not work in PowerShell version 2.

I recently needed to work with a file containing data structured in fixed column width lines. The specification given to me could, for example, say that the first column, which is 9 characters, contains the First Name of a person, the second column, 10 characters, is the Last Name, the third column, 14 characters, is the country and finally the last two columns on each line is an abbreviation of the persons first and last name.

An example data file, using person information from different Wikipedia articles, could be something like the following

Ada    Lovelace  UK            al
Alfred Nobel     Sweden        an
GalileoGalilei   Italy         gg
Sophie KowalevskiRussian Empiresk
Thomas Edison    USA           te
Wang   Zhenyi    China         wz

Since I had several files with several different format, some of which had a first line which contained column headers, I wanted a reusable function for this parsing. The problem seems common enough to have a function built-in, but I did not know of such a function, so I created the ConvertFrom-FixedLengths function. If someone could point me to such a function, or a better approach, please let me know in the comments to this post.

Using the ConvertFrom-FixedLengths

The actual function script can be found last in this blog post, but here's a few usage samples.

Piping Get-Content data into the function

The scenario I wanted was just to pipe the result of Get-Content from the sample file above into the function. Given that we have a c:\data.txt file, containing the sample content above, just run the following command:

PS C:\> Get-Content .\data.txt | ConvertFrom-FixedLengths 7,10,14,2 -Trim | Format-Table

The Trim switch tells the function to remove any leading and trailing spaces on the property values. This command ended up providing the following output:

Column1                Column2                Column3                Column4
-------                -------                -------                -------
Ada                    Lovelace               UK                     al
Alfred                 Nobel                  Sweden                 an
Galileo                Galilei                Italy                  gg
Sophie                 Kowalevski             Russian Empire         sk
Thomas                 Edison                 USA                    te
Wang                   Zhenyi                 China                  wz

Using the first line to specify headers

In some of the files I had, the first line was a header line, so I wanted the resulting objects property names to be named after those headers. So, to test this, just create some sample data where the first line is a header line, and pipe that data into the function:

PS C:\> $peopleOrderedByFirstNameWithHeaders = @"
FirstNameLastName  Country       FL
Ada      Lovelace  UK            al
Alfred   Nobel     Sweden        an
Galileo  Galilei   Italy         gg
Sophie   KowalevskiRussian Empiresk
Thomas   Edison    USA           te
Wang     Zhenyi    China         wz
"@ -split [Environment]::NewLine

PS C:\> $peopleOrderedByFirstNameWithHeaders |
    ConvertFrom-FixedLengths 9,10,14,2 -Trim -HeadersFromFirstLine | 
    Format-Table
    
FirstName              LastName               Country                FL
---------              --------               -------                --
Ada                    Lovelace               UK                     al
Alfred                 Nobel                  Sweden                 an
Galileo                Galilei                Italy                  gg
Sophie                 Kowalevski             Russian Empire         sk
Thomas                 Edison                 USA                    te
Wang                   Zhenyi                 China                  wz

The ConvertFrom-FixedLengths function

Here's the actual function I ended up with, toghether with comment based help for the function:

<#
.Synopsis
   Converts data from an array of fixed length column structured strings to objects with a property for each column.
.DESCRIPTION
   Expects one or more strings of fixed length column data and parses these strings into one object for each matching string. 
   
   The resulting object will have one property for each column in the data. The property names will be Column1, Column2, ..., ColumnN if the HeadersFromFirstLine switch is not used.
.PARAMETER InputObject
   Specifies the array of strings which is the data to be used. In an entry in this array does not fullfill the structure specified by the ColumnWidths parameter it will be ignored. For each string, the whole string, from start to end, must match the format in order for the string to be included.
.PARAMETER ColumnWidths
   Specifies the width for each of the columns in the input data. Each entry in the array passed in determines the number of characters expected in the column of the corresponding index.
.PARAMETER Trim
   Specifies whether or not padding (leading or trailing) spaces should be removed from the property values.
.PARAMETER HeadersFromFirstLine
   Specifies whether or not the first entry in the InputObject array should be removed from the result list and instead be used to set the property names for the resulting objects.
.INPUTS
   Piping an array of strings to this function will set the InputObject parameter. For additional help, see Get-Help ConvertFrom-FixedLengths -Parameter InputObject
.OUTPUTS
   One object for each entry in the InputObject array which fits the format described by the ColumnWidths parameter. 

   The properties of the objects, if the HeadersFromFirstLine switch was not provided, will be named Column1, Column2, Column3, ..., ColumnN.

   If the HeadersFromFirstLine switch is provided, the properties will be named based on the names specified in the first line. If the first line does not conform to the format specified by the ColumnWidths property, the first line will be ignored and the properties will still be named Column1, Column2, ..., ColumnN.
.NOTES
   Author: Robert Westerlund
   Date:   2014-03-23  
.EXAMPLE

    PS C:\> Get-Content .\data.txt | ConvertFrom-FixedLengths 9,10,14,2 | Format-Table

    Just pipe the result of the Get-Content cmdlet to this function and provide the column widths.

.EXAMPLE

    PS C:\> Get-Content .\data.txt | ConvertFrom-FixedLengths 9,10,14,2 -Trim | Format-Table
    
    To remove padding spaces in the data, use the Trim switch.
    
.EXAMPLE

    PS C:\> Get-Content .\data.txt | ConvertFrom-FixedLengths 9,10,14,2 -Trim -HeadersFromFirstLine | Format-Table

    If the first line in the data file is a header line use the HeadersFromFirstLine switch

.EXAMPLE

    PS C:\>

    Below is an example where the data is a string array created in memory (sample names and locations taken from different Wikipedia articles).

    PS C:\> $peopleOrderedByFirstName = @"
    >> Ada    Lovelace  UK            al
    >> Alfred Nobel     Sweden        an
    >> GalileoGalilei   Italy         gg
    >> Sophie KowalevskiRussian Empiresk
    >> Thomas Edison    USA           te
    >> Wang   Zhenyi    China         wz
    >> "@ -split [Environment]::NewLine
    
    PS C:\> $peopleOrderedByFirstName | 
    >> ConvertFrom-FixedLengths 7,10,14,2 -Trim | 
    >> Format-Table

.EXAMPLE

    PS C:\>

    This sample uses the first line of the data to set the property names for the resulting objects (sample names and locations taken from different Wikipedia articles).

    PS C:\> $peopleOrderedByFirstNameWithHeaders = @"
    >> FirstNameLastName  Country       FL
    >> Ada      Lovelace  UK            al
    >> Alfred   Nobel     Sweden        an
    >> Galileo  Galilei   Italy         gg
    >> Sophie   KowalevskiRussian Empiresk
    >> Thomas   Edison    USA           te
    >> Wang     Zhenyi    China         wz
    >> "@ -split [Environment]::NewLine

    PS C:\> $peopleOrderedByFirstNameWithHeaders |
    >> ConvertFrom-FixedLengths 9,10,14,2 -Trim -HeadersFromFirstLine | 
    >> Format-Table

#>
function ConvertFrom-FixedLengths
{
    [OutputType([PSCustomObject])]
    PARAM(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string[]]$InputObject
    ,
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [int[]]$ColumnWidths
    ,
        [switch]$Trim
    ,
        [switch]$HeadersFromFirstLine
    )
    BEGIN
    {
        #Ensure that no columns are of width 0 or lower.
        $valuesLowerThanOrEqualToZero = $ColumnWidths | Where { $_ -le 0 }
        if ($valuesLowerThanOrEqualToZero.Length -gt 0)
        {
            throw "The column width must be a value higher than 0. The value(s) '$($valuesLowerThanOrEqualToZero -join "', '")' is not valid for column width"
        }

        #Build the regex string for parsing the columns
        $regex = '^'
        foreach($width in $ColumnWidths)
        {
            $regex += "(.{$width})"
        }
        $regex += '$'
        Write-Verbose "Using the regex '$regex' for parsing the string"

        #Create an array holding the header names we want to use, so we can get headers from the first line
        $haveHeadersBeenRetrieved = $false
        $columnWidthLength = $ColumnWidths.Length
        #We use the start index 1 since it feels more natural for property name
        $headers = (1..$columnWidthLength) | Foreach { "Column$_" }
        
        #Build a script block which will be used to create PSObjects from the input data
        $NewObjectScript = {
            PARAM(
                [Microsoft.PowerShell.Commands.MatchInfo]
                $MatchInfo
            )

            $groups = $MatchInfo.Matches.Groups
            $properties = [ordered]@{}
            
            for($index = 0; $index -lt $columnWidthLength; $index ++)
            {
                #The group at index 0 is the whole matching string, so the first capture group is at 1
                $value = $groups[$index + 1].Value
                if ($Trim)
                {
                    $value = $value.Trim()
                }
                $properties.($headers[$index]) = $value 
            }

            Write-Output (New-Object PSCustomObject -Property $properties)
        }
    }
    PROCESS
    {
        if ($HeadersFromFirstLine -and -not $haveHeadersBeenRetrieved)
        {
            #Remove the first line from the input object and use the regular expression to retrieve the headers from that line
            $InputObject | 
                Select -First 1 |
                Select-String -Pattern $regex |
                Foreach {
                    $groups = $_.Matches.Groups
                    $headers = (1..$columnWidthLength) | Foreach { 
                        $groups[$_].Value.Trim()
                    }
                }
            
            #Verify that no two headers are the same
            $duplicateHeaders = $headers | Where { $current = $_; @($Headers | Where {$_ -eq $current}).Length -gt 1 } | Get-Unique -AsString
            if ($duplicateHeaders)
            {
                throw "Cannot use the same header for two columns. Duplicate header(s) found: $($duplicateHeaders -join ', ')"
            }
            Write-Verbose "Using the following header(s) for property names: $($headers -join ', ')"

            #Ensure that we don't do this again and that the rest of the processing doesn't use the header line
            $haveHeadersBeenRetrieved = $true
            $InputObject = $InputObject | Select -Skip 1
        }

        #Process the actual strings based on the regex created in the BEGIN scriptblock
        $InputObject | 
            Select-String -Pattern $regex |
            Foreach {& $NewObjectScript $_ }
    }
}

Working with Git on remote computer using a PSDrive

I have a web site which I update using a git repository. I make my changes, push the changes to a git service provider (e.g. GitHub) and then pull the latest version on the server. However, I don't want to have it automatically pull any changes, but I want to manually trigger a pull at the times I want the site to update.

I wanted to avoid Remote Desktop and also wanted to stay in my favorite console; the PowerShell console. I couldn't do it by using ordinary PowerShell remoting, since the git pull will ask me for username and password, which won't work via a PowerShell session. What I ended up doing was setting up a server share (this could be the root admin share, if wanted) as a PSDrive and then run my git command from the PSDrive.

PS C:\> New-PSDrive -Name MyWebServer -PSProvider FileSystem -Root \\WebServer01\MyGitRootShare -Credential (Get-Credential MYDOMAIN\MyUserName)
PS C:\> cd MyWebServer:
PS MyWebServer:\>git pull origin master
Username for 'https://mygithost.com': MyUserName
Password for 'https://MyUserName@mygithost.com':

Using a PSDrive (mapped network drive) PowerShell was perfectly fine displaying the interactive prompt from Git, since it was executing git locally and not via remoting.

Git seemed slower working via a PSDrive than working locally, but that was expected and the difference wasn't noticable enough for me to care.

Creating a Composite DSC Configuration with Parameters

While answering a question on StackOverflow I realized that I wanted to write a longer guide on the matter, which might not be a good fit for the Question and Answer format of StackOverflow. So, why not make a blog post of it?

The question was about how to create a composite Desired State Configuration (DSC) resource which has parameters. It might be valuable to know that I'm no expert on Desired State Configuration and tried many different things before I tried one that works. There might be other ways to achieve the goal, but this is a description of at least one way. In the examples, I will use BaseConfig for config name and MyParameter for parameter name.

Parameters to a Composite Configuration which is an ordinary module – not suggested

When a Composite Configuration is created as an ordinary module (directly in the C:\Program Files\WindowsPowerShell\Modules\MyModuleName, for example), it seems like it behaves like an ordinary Cmdlet. This means, to pass parameters to the composite configuration I had to do:

Import-DscResource -ModuleName BaseConfig 

Node localhost 
{ 
    BaseConfig Common -MyParameter "My Parameter Value" 
    { 
    } 
}

Worth noting is that I don't know if this would behave as expected for a DSC resource in other matters or not.

Also, if you create your composite configuration as a base module instead of a DSCResource within a module you will have to explicitly import the module since DSC won't do it automatically for you.

A Composite Configuration which supports parameters the right way

Since C:\Program Files\WindowsPowerShell\Modules is a long path and also is the folder in which we will should create our composite resource for it to be available for all users, I will shorten the path in the scripts below to display as C:\...\Modules and then subfolders are displayed as they are normally

In order to create a composite configuration which supports parameters, I had to make a dummy container module. These could, of course, contain implementation, but I only created an empty psm1 file and a psd1 file pointing to that psm1 file, using the following commands.

PS C:\...\Modules> md MyDscResources
PS C:\...\Modules> cd .\MyDscResources
PS C:\...\Modules\MyDscResources> "" > MyDscResources.psm1
PS C:\...\Modules\MyDscResources> New-ModuleManifest -Path .\MyDscResources.psd1 -RootModule MyDscResources.psm1

After making the empty container module, create a DSC resource folder (the name of the folder must be DSCResources) and then a folder for the composite configuration.

PS C:\...\Modules\MyDscResources> md DSCResources
PS C:\...\Modules\MyDscResources> cd .\DSCResources
PS C:\...\Modules\MyDscResources\DSCResources> md BaseConfig
PS C:\...\Modules\MyDscResources\DSCResources> cd .\BaseConfig

When we have the folder for our DSC Resource Composite Configuration, we should create the .schema.psm1 file, which should contain the composite configuration, as well as a .psd1 file which points to the module file. Note that the .schema.psm1 part of the filename must be matched exactly, since the PSDesiredStateConfiguration module actually looks specifically for this hard coded file extension for composite resources. Enter the following script into the BaseConfig.schema.psm1 file:

Configuration BaseConfig
{
    PARAM (
        $FileContents
    )
    
    File RootFile1
    {
        DestinationPath = "C:\FileAtRoot1.txt"
        Ensure = "Present"
        Contents = $FileContents
    }
    File RootFile2
    {
        DestinationPath = "C:\FileAtRoot2.txt"
        Ensure = "Present"
        Contents = $FileContents
    }
}

Then create a module manifest for the composite configuration:

PS C:\...\Modules\MyDscResources\DSCResources\BaseConfig> New-ModuleManifest -Path .\BaseConfig.psd1 -RootModule BaseConfig.schema.psm1

That's all which is needed to create the composite configuration.

Test the Composite Configuration

In order to test that our composite configuration works as expected, we need to create a configuration which uses the composite configuration we have created. The folder location is no longer important, so let's create the configuration in a C:\temp folder

PS C:\Program Files\WindowsPowerShell\Modules\MyDscResources\DSCResources\BaseConfig> cd\
PS C:\> md temp
PS C:\> cd temp
PS C:\temp> notepad ConfigurationTest.ps1

Into this ConfigurationTest.ps1 file, enter the following script:

Configuration ConfigurationTest
{
    Import-DscResource -Name BaseConfig
    
    Node localhost
    {
        BaseConfig Commoon
        {
            FileContents = "This is the file contents we want"
        }
    }
}

ConfigurationTest

Now that we have our composite configuration and also a configuration which uses this, let's execute the configuration script to create the MOF files and then use the Start-DscConfiguration cmdlet to let DSC execute the configuration:

PS C:\temp> .\ConfigurationTest.ps1
PS C:\temp> Start-DscConfiguration ConfigurationTest

Once DSC has completed executing the configuration we should have the expected files, C:\FileAtRoot1.txt and \FileAtRoot2.txt which both have the parameter value as contents.

"GetMemberName" or "getting rid of (some) magic strings"

Earlier today I had another discussion() with a co-worker of mine. This discussion related to magic strings and potential ways to get rid of them. I have previously mentioned that I dislike magic strings, but I haven't mentioned why. Nor have I mentioned in which circumstances which I dislike seeing them.

When do I use magic strings

There are cases where magic strings are pretty useful. An example of this is in communicating between different applications, where strings are more descriptive than using, for example, an integer. Thus, if I send a message from application A to application B telling it to do “<action>print</action>” on something, it is a lot more descriptive and easy to debug than if it would be “<action>3</action>”. The same goes for the code listening to this message.

switch(action)
{
    case “print”:
        //Do the printing
        break;
}

it is a lot better than

switch(action)
{
    case 3:
        //Do the printing
        break;
}

However, I often try to limit the risk of errors, when using magic strings, for example by creating an XSD forcing an enumeration constraint (only allowing the content of the action element to be one of a limited set of values). This also has the benefit of making the message easier to use. (Whether it could still be called a magic string after enforcing an enumeration constraint on the value is a question of definitions, so in general I try to avoid the pitfalls of magic strings.)

When do I try to avoid magic strings

On the other hand, there are a lot of cases where I believe that magic strings are nothing but evil (although in some cases they may be necessary evil). One example of this is the INotifyPropertyChanged interface. Another such example is throwing ArgumentNullExceptions.

public class MyClass:INotifyPropertyChanged
{
    public MyClass(IRepository repository)    
    {
        if (repository == null)
        throw new ArgumentNullException(“repository”);
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnNotifyPropertyChanged(“Name”);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
}

What happens when we change the IRepository to be a IDataRepository and therefore also renames the constructor parameter to dataRepository? What happens when we rename the Name property to Title? Well, in most cases we will remember to change the string as well, but every now and then we will forget to change the string. Also, sometimes we will misspell the property name, e.g. writing -“Neme” instead of “Name”. Of course, I could unit test all the property setters to make sure that the NotifyPropertyChanged is fired with the correct propertyName. While this might be a good (or bad) idea in and of itself, we still would have to remember to change the contents of the string in the unit test when we rename the property.

Expressions to the rescue

With C# 3.0 we got lambda expressions, which I am very fond of. Our nice lambda expressions are a lot better as a syntax for writing anonymous methods than what anonymous delegates ever were. The sometimes well-known secret here, however, is that the same lambda expression code could mean two completely different things, depending on the context. Given the following code:

DoStuff<string>(stringValue => Console.WriteLine(stringValue));

We would pass completely different things to our DoStuff-method depending on how that method is defined (Which could be compared to sending a constant integer 1 as a parameter to method. If the method takes an integer, the parameter would be compiled as an integer but if the parameter is defined as a double, the compiler would help us and change the 1 to a double with the value 1.0d). If the parameter is defined as an Action<string>, then we would receive a precompiled Action which we could use. If, on the other hand, the parameter is defined as Expression<Action<string>> then we would instead get an expression tree. Using this expression tree, we could compile and execute it if we want to, but we also have the possibility to examine the expression tree (which is very useful, for example when creating an IQueryable or IQbservable).

The GetMemberName-method

What I would want in the above examples is that if I would rename the property or parameter using the refactoring tools in Visual Studio, the string would automatically be updated as well. And if I, for some reason, would have misspelled or forgot to update the string, I would like a compiler error. The GetMemberName-method will help us achieve this goal.

public static class ObjectExtensions
{
    public static string GetMemberName<T, K>(this T obj, Expression<Func<T, K>> expression)
    {
        if (expression == null)
            obj.GetMemberName(_ => expression);
        MemberExpression memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
            throw new ArgumentException("Expression of type " 
                + expression.Body.Type.ToString() 
                + " is not supported by the GetMemberName method."
                + " Only MemberExpressions are currently supported.", obj.GetMemberName(_ => expression));
        return memberExpression.Member.Name;
    }
}

We could then change our code above to something similar to the following:

public class MyClass:INotifyPropertyChanged
{
    public MyClass(IRepository repository)    
    {
        if (repository == null)
            throw new ArgumentNullException(this.GetMemberName(_ => repository));
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnNotifyPropertyChanged(this.GetMemberName(_ => Name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
}

Tiny drawbacks

Of course, for some unfortunate reason, there are no silver bullets which solve every problem, even though this one is at least silver coated. The drawback of using the GetMemberName instead of using a constant string is performance. I have performed very naive performance tests on the GetMemberName-method and it has shown that the method call took up to 30 milliseconds to perform on my laptop (which isn’t a very powerful laptop). In almost all cases I believe these milliseconds are worth getting rid of the strings, but if I would set the property 100 times per second this could be a problem (on the other hand, if I update it that frequently, perhaps it isn't a good fit for INotifyPropertyChanged). Therefore, I try to use this approach as often as I can, instead of using unnecessary magic string, and only if it would become a problem, I would consider writing the name as a string.

Unit Testing

It could be added, of course, that if you have unit tests which cover the PropertyChanged events when setting parameters this could be a non-issue, as long as you start a property rename with renaming in the tests and there renaming the string. Perhaps the GetMemberName method could be good to use in the unit test and to not use in the application code?

Custom scroll buttons for the ScrollViewer control in Silverlight

Earlier today I had a discussion with a co-worker who needed to replace the default template of the ScrollViewer control, in order to replace the ScrollBar with custom buttons. He had found some example of doing this in WPF, but the same sample did not work in Silverlight (the samples relied on routed command which aren’t available in Silverlight) so I decided to write up a sample of my own.

Disclaimer: The sample is very rudimentary and may not be the best way to achieve this (also the placement of the commands might be questionable). Use the sample at your own risk.

To begin with, we need a ScrollViewer with some content.

<Grid x:Name="LayoutRoot" Background="White" Height="100" Width="120">
    <ScrollViewer>
        <StackPanel>
            <TextBlock Text="Text1"/>
            <TextBlock Text="Text2"/>
            <TextBlock Text="Text3"/>
            <TextBlock Text="Text4"/>
            <TextBlock Text="Text5"/>
            <TextBlock Text="Text6"/>
            <TextBlock Text="Text7"/>
            <TextBlock Text="Text8"/>
            <TextBlock Text="Text9"/>
        </StackPanel>
    </ScrollViewer>
</Grid>

Additionally, we will be using a stripped down version of the RelayCommand. I use a stripped down version since I really don’t need any more functionality for this sample.

public class RelayCommand<T>:ICommand
{
    private Action<T> _action;

    public RelayCommand(Action<T> action)
    {
        this._action = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        if (!(parameter is T))
            throw new ArgumentException("The parameter must be of type T", "parameter");
        _action((T)parameter);
    }
}

The default look of the ScrollViewer control, using the above Xaml looks similar to this:

The default look of the ScrollViewer control, using the Content we supplied

And our goal is to make it look like this:

The modified look of the ScrollViewer control, using buttons instead of the ScrollBar, which we have as our aim

Quite an improvement, right?

I admit that it might not be prettiest design for my custom scroll buttons. To my defence I will say that beauty is not the aim of this post and… well, at least it works.

To get the ScrollViewer to look like what we want, we start by changing the declaration of the ScrollViewer to start using a custom template (if you do this in production code, you might want to define it as a style and set the Template property to be your ContentTemplate, especially since you will probably want to set other properties as well, but in order to keep the code a little shorter here, we’ll just set the template directly) which we will define later. The new declaration of the ScrollViewer should be:

<ScrollViewer Template="{StaticResource MyScrollViewer}">
...

The next step is to create the actual Template that we have just referenced. In our template, we’ll create two RepeatButtons (using RepeatButtons instead of Buttons allows the user to keep the button pressed to keep scrolling until released), to serve as up and down buttons, and between them we’ll place the ScrollContentPresenter (which will display the content of the ScrollViewer control, i.e. the TextBlocks).

<ControlTemplate x:Key="MyScrollViewer" TargetType="ScrollViewer">
    <StackPanel Width="100">
        <RepeatButton Content="Up" Command="{Binding ScrollUpCommand, ElementName=_this}"
		CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
        <ScrollContentPresenter Height="50" x:Name="ScrollContentPresenter"/>
        <RepeatButton Content="Down" Command="{Binding ScrollDownCommand, ElementName=_this}"
		CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
    </StackPanel>
</ControlTemplate>

So, what is the ScrollUpCommand used in the code above? The ScrollUpCommand, as well as the ScrollDownCommand, is defined in the code behind of the control, using the following code:

public ICommand ScrollUpCommand
{
	get
	{
		return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineUp());
	}
}

public ICommand ScrollDownCommand
{
	get
	{
		return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineDown());
	}
}

And there we have it, our nice little ScrollViewer without the default ScrollBar. The secret sauce lies in the CommandParameter, sending the ScrollContentPresenter which we want to scroll as a parameter to the command when it executes. Have fun with the code! Here is the full code for the sample:

MainPage.xaml:

<UserControl x:Class="SilverlightApplication11.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" x:Name="_this">
    <UserControl.Resources>
        <ControlTemplate x:Key="MyScrollViewer" TargetType="ScrollViewer">
            <StackPanel Width="100">
                <RepeatButton Content="Up" Command="{Binding ScrollUpCommand, ElementName=_this}" 
			CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
                <ScrollContentPresenter Height="50" x:Name="ScrollContentPresenter"/>
                <RepeatButton Content="Down" Command="{Binding ScrollDownCommand, ElementName=_this}" 
			CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
            </StackPanel>
        </ControlTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" Height="100" Width="120">
        <ScrollViewer Template="{StaticResource MyScrollViewer}">
            <StackPanel>
                <TextBlock Text="Text1"/>
                <TextBlock Text="Text2"/>
                <TextBlock Text="Text3"/>
                <TextBlock Text="Text4"/>
                <TextBlock Text="Text5"/>
                <TextBlock Text="Text6"/>
                <TextBlock Text="Text7"/>
                <TextBlock Text="Text8"/>
                <TextBlock Text="Text9"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</UserControl>

MainPage.xaml.cs:

using System.Windows.Controls;
using System.Windows.Input;

namespace SilverlightApplication11
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        public ICommand ScrollUpCommand
        {
            get
            {
                return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineUp());
            }
        }

        public ICommand ScrollDownCommand
        {
            get
            {
                return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineDown());
            }
        }
    }
}

RelayCommand.cs:

using System;
using System.Windows.Input;

namespace SilverlightApplication11
{
    public class RelayCommand<T>:ICommand
    {
        private Action<T> _action;

        public RelayCommand(Action<T> action)
        {
            this._action = action;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            if (!(parameter is T))
                throw new ArgumentException("The parameter must be of type T", "parameter");
            _action((T)parameter);
        }
    }
}